#include "jsonOperation.h"
#include <json/json.hpp>
#include <utils.h>
using nlohmann::json;
using namespace onvif_tool_json_operation;
using namespace std;

optional<string> jsonOperation::parseConfig(string &jsonStr, tt__Config *config)
{
    string errPrefix = "parseConfig error";
    if (config == nullptr)
    {
        return makeErrorStr(errPrefix, "param \"config\" is null");
    }
    json j;

    j["name"] = config->Name ? string(config->Name) : string("");
    j["type"] = config->Type ? string(config->Type) : string("");

    if (config->Parameters != nullptr)
    {
        vector<json> simpleItems;

        for (int i = 0; i < config->Parameters->__sizeSimpleItem; i++)
        {
            json item;
            item["name"] = config->Parameters->SimpleItem[i].Name ? string(config->Parameters->SimpleItem[i].Name) : string("");
            item["value"] = config->Parameters->SimpleItem[i].Value ? string(config->Parameters->SimpleItem[i].Value) : string("");
            simpleItems.push_back(item);
        }
        j["simpleItem"] = simpleItems;

        vector<json> elementItems;

        for (int i = 0; i < config->Parameters->__sizeElementItem; i++)
        {
            json item;
            item["name"] = config->Parameters->ElementItem[i].Name ? string(config->Parameters->ElementItem[i].Name) : string("");
            elementItems.push_back(item);
        }
        j["elementItem"] = elementItems;
    }

    jsonStr = j.dump();
    return nullopt;
}

optional<string> jsonOperation::parse1DSpace(string &jsonStr, tt__Space1DDescription *space)
{
    string errPrefix = "parse1DSpace error";
    if (space == nullptr)
    {
        return makeErrorStr(errPrefix, "param \"space\" is null");
    }
    json j;
    j["uri"] = string(space->URI);
    j["xRange"] = std::to_string(space->XRange->Min) + " ~ " + std::to_string(space->XRange->Max);
    jsonStr = j.dump();
    return nullopt;
}

optional<string> jsonOperation::parse2DSpace(string &jsonStr, tt__Space2DDescription *space)
{
    string errPrefix = "parse2DSpace error";
    if (space == nullptr)
    {
        return makeErrorStr(errPrefix, "param \"space\" is null");
    }
    json j;
    j["uri"] = string(space->URI);
    j["xRange"] = std::to_string(space->XRange->Min) + " ~ " + std::to_string(space->XRange->Max);
    j["yRange"] = std::to_string(space->YRange->Min) + " ~ " + std::to_string(space->YRange->Max);
    jsonStr = j.dump();
    return nullopt;
}

optional<string> jsonOperation::parsePTZSpace(string &jsonStr, tt__PTZSpaces *space)
{
    string errPrefix = "parsePTZSpace error";
    if (space == nullptr)
    {
        return makeErrorStr(errPrefix, "param \"space\" is null");
    }
    json j;

    // absolutePanTiltPositionSpace
    vector<json> absolutePanTiltPositionSpace;
    for (int i = 0; i < space->__sizeAbsolutePanTiltPositionSpace; i++)
    {
        string jsonStr_;
        if (auto err = parse2DSpace(jsonStr_, space->AbsolutePanTiltPositionSpace[i]); err)
        {
            return makeErrorStr(errPrefix, *err);
        }

        json item = json::parse(jsonStr_);
        absolutePanTiltPositionSpace.push_back(item);
    }
    j["absolutePanTiltPositionSpace"] = absolutePanTiltPositionSpace;

    // absoluteZoomPositionSpace
    vector<json> absoluteZoomPositionSpace;
    for (int i = 0; i < space->__sizeAbsoluteZoomPositionSpace; i++)
    {
        string jsonStr_;
        auto result = parse1DSpace(jsonStr_, space->AbsoluteZoomPositionSpace[i]);
        if (auto err = parse1DSpace(jsonStr_, space->AbsoluteZoomPositionSpace[i]); err)
        {
            return makeErrorStr(errPrefix, *err);
        }

        json item = json::parse(jsonStr_);
        absoluteZoomPositionSpace.push_back(item);
    }
    j["absoluteZoomPositionSpace"] = absoluteZoomPositionSpace;

    // relativePanTiltTranslationSpace
    vector<json> relativePanTiltTranslationSpace;
    for (int i = 0; i < space->__sizeRelativePanTiltTranslationSpace; i++)
    {
        string jsonStr_;
        if (auto err = parse2DSpace(jsonStr_, space->RelativePanTiltTranslationSpace[i]); err)
        {
            return makeErrorStr(errPrefix, *err);
        }

        json item = json::parse(jsonStr_);
        relativePanTiltTranslationSpace.push_back(item);
    }
    j["relativePanTiltTranslationSpace"] = relativePanTiltTranslationSpace;

    // relativeZoomTranslationSpace
    vector<json> relativeZoomTranslationSpace;
    for (int i = 0; i < space->__sizeRelativeZoomTranslationSpace; i++)
    {
        string jsonStr_;
        if (auto err = parse1DSpace(jsonStr_, space->RelativeZoomTranslationSpace[i]); err)
        {
            return makeErrorStr(errPrefix, *err);
        }

        json item = json::parse(jsonStr_);
        relativeZoomTranslationSpace.push_back(item);
    }
    j["relativeZoomTranslationSpace"] = relativeZoomTranslationSpace;

    // continuousPanTiltVelocitySpace
    vector<json> continuousPanTiltVelocitySpace;
    for (int i = 0; i < space->__sizeContinuousPanTiltVelocitySpace; i++)
    {
        string jsonStr_;
        if (auto err = parse2DSpace(jsonStr_, space->ContinuousPanTiltVelocitySpace[i]); err)
        {
            return makeErrorStr(errPrefix, *err);
        }

        json item = json::parse(jsonStr_);
        continuousPanTiltVelocitySpace.push_back(item);
    }
    j["continuousPanTiltVelocitySpace"] = continuousPanTiltVelocitySpace;

    // ContinuousZoomVelocitySpace
    vector<json> continuousZoomVelocitySpace;
    for (int i = 0; i < space->__sizeContinuousZoomVelocitySpace; i++)
    {
        string jsonStr_;
        if (auto err = parse1DSpace(jsonStr_, space->ContinuousZoomVelocitySpace[i]); err)
        {
            return makeErrorStr(errPrefix, *err);
        }

        json item = json::parse(jsonStr_);
        continuousZoomVelocitySpace.push_back(item);
    }
    j["continuousZoomVelocitySpace"] = continuousZoomVelocitySpace;

    // PanTiltSpeedSpace
    vector<json> panTiltSpeedSpace;
    for (int i = 0; i < space->__sizePanTiltSpeedSpace; i++)
    {
        string jsonStr_;
        if (auto err = parse1DSpace(jsonStr_, space->PanTiltSpeedSpace[i]); err)
        {
            return makeErrorStr(errPrefix, *err);
        }

        json item = json::parse(jsonStr_);
        panTiltSpeedSpace.push_back(item);
    }
    j["panTiltSpeedSpace"] = panTiltSpeedSpace;

    // ZoomSpeedSpace
    vector<json> zoomSpeedSpace;
    for (int i = 0; i < space->__sizeZoomSpeedSpace; i++)
    {
        string jsonStr_;
        if (auto err = parse1DSpace(jsonStr_, space->ZoomSpeedSpace[i]); err)
        {
            return makeErrorStr(errPrefix, *err);
        }

        json item = json::parse(jsonStr_);
        zoomSpeedSpace.push_back(item);
    }
    j["zoomSpeedSpace"] = zoomSpeedSpace;

    jsonStr = j.dump();
    return nullopt;
}

optional<string> jsonOperation::parsePTZVector(string &jsonStr, tt__PTZVector *PTZVector)
{
    string errPrefix = "parsePTZVector error";
    if (PTZVector == nullptr)
    {
        return makeErrorStr(errPrefix, "param \"PTZVector\" is null");
    }
    json j;

    if (PTZVector->Zoom != nullptr)
    {
        j["zoom"]["x"] = to_string(PTZVector->Zoom->x);
        j["zoom"]["space"] = PTZVector->Zoom->space ? string(PTZVector->Zoom->space) : string("");
    }

    if (PTZVector->PanTilt != nullptr)
    {
        j["panTilt"]["x"] = to_string(PTZVector->PanTilt->x);
        j["panTilt"]["y"] = to_string(PTZVector->PanTilt->y);
        j["panTilt"]["space"] = PTZVector->PanTilt->space ? string(PTZVector->PanTilt->space) : string("");
    }

    jsonStr = j.dump();
    return nullopt;
}

optional<string> jsonOperation::parseGeoLocation(string &jsonStr, tt__GeoLocation *location)
{
    string errPrefix = "parseGeoLocation error";
    if (location == nullptr)
    {
        return makeErrorStr(errPrefix, "param \"location\" is null");
    }
    json j;
    j["longitude"] = location->lon ? to_string(*(location->lon)) : string("");
    j["latitude"] = location->lat ? to_string(*(location->lat)) : string("");
    j["elevation"] = location->elevation ? to_string(*(location->elevation)) : string("");

    jsonStr = j.dump();
    return nullopt;
}

optional<string> jsonOperation::parseGeoOrientation(string &jsonStr, tt__GeoOrientation *orientation)
{
    string errPrefix = "parseGeoOrientation error";
    if (orientation == nullptr)
    {
        return makeErrorStr(errPrefix, "param \"orientation\" is null");
    }
    json j;
    j["roll"] = orientation->roll ? to_string(*(orientation->roll)) : string("");
    j["pitch"] = orientation->pitch ? to_string(*(orientation->pitch)) : string("");
    j["yaw"] = orientation->yaw ? to_string(*(orientation->yaw)) : string("");

    jsonStr = j.dump();
    return nullopt;
}

optional<string> jsonOperation::parseLocalLocation(string &jsonStr, tt__LocalLocation *location)
{
    string errPrefix = "parseLocalLocation error";
    if (location == nullptr)
    {
        return makeErrorStr(errPrefix, "param \"location\" is null");
    }
    json j;
    j["x"] = location->x ? to_string(*(location->x)) : string("");
    j["y"] = location->y ? to_string(*(location->y)) : string("");
    j["z"] = location->z ? to_string(*(location->z)) : string("");

    jsonStr = j.dump();
    return nullopt;
}

optional<string> jsonOperation::parseLocalOrientation(string &jsonStr, tt__LocalOrientation *orientation)
{
    string errPrefix = "parseLocalOrientation error";
    if (orientation == nullptr)
    {
        return makeErrorStr(errPrefix, "param \"orientation\" is null");
    }
    json j;
    j["pan"] = orientation->pan ? to_string(*(orientation->pan)) : string("");
    j["tilt"] = orientation->tilt ? to_string(*(orientation->tilt)) : string("");
    j["roll"] = orientation->roll ? to_string(*(orientation->roll)) : string("");

    jsonStr = j.dump();
    return nullopt;
}

optional<string> jsonOperation::parseLocationEntity(string &jsonStr, tt__LocationEntity *entity)
{
    string errPrefix = "parseLocationEntity error";
    if (entity == nullptr)
    {
        return makeErrorStr(errPrefix, "param \"entity\" is null");
    }
    json j;

    j["entity"] = entity->Entity ? string(entity->Entity) : string("");
    j["token"] = entity->Token ? string(entity->Token) : string("");
    j["fixed"] = entity->Fixed ? (*entity->Fixed ? string("true") : string("false")) : string("");
    j["geoSource"] = entity->GeoSource ? string(entity->GeoSource) : string("");
    j["autoGeo"] = entity->AutoGeo ? (*entity->AutoGeo ? string("true") : string("false")) : string("");

    string jsonResponse;
    if (auto err = parseGeoLocation(jsonResponse, entity->GeoLocation); !err)
    {
        j["geoLocation"] = json::parse(jsonResponse);
    }

    if (auto err = parseGeoOrientation(jsonResponse, entity->GeoOrientation); !err)
    {
        j["geoOrientation"] = json::parse(jsonResponse);
    }

    if (auto err = parseLocalLocation(jsonResponse, entity->LocalLocation); !err)
    {
        j["localLocation"] = json::parse(jsonResponse);
    }

    if (auto err = parseLocalOrientation(jsonResponse, entity->LocalOrientation); !err)
    {
        j["localOrientation"] = json::parse(jsonResponse);
    }

    jsonStr = j.dump();
    return nullopt;
}

optional<string> jsonOperation::parseNetworkInterface(string &jsonStr, tt__NetworkInterface *interface_)
{
    string errPrefix = "parseNetworkInterface error";
    if (interface_ == nullptr)
    {
        return makeErrorStr(errPrefix, "param \"interface_\" is null");
    }

    json j;

    j["enabled"] = interface_->Enabled ? "true" : "false";
    j["token"] = interface_->token ? string(interface_->token) : string("");
    if (interface_->Info != nullptr)
    {
        j["name"] = interface_->Info->Name ? string(interface_->Info->Name) : string("");
        j["mac"] = interface_->Info->HwAddress ? string(interface_->Info->HwAddress) : string("");
        j["MTU"] = interface_->Info->MTU ? to_string(*interface_->Info->MTU) : string("");
    }

    if (interface_->Link != nullptr)
    {
        if (interface_->Link->AdminSettings != nullptr)
        {
            j["adminSettings"]["autoNegotiation"] = interface_->Link->AdminSettings->AutoNegotiation ? string("true") : string("false");
            j["adminSettings"]["speed"] = to_string(interface_->Link->AdminSettings->Speed);
            j["adminSettings"]["duplex"] = interface_->Link->AdminSettings->Duplex == tt__Duplex__Full ? string("full") : string("half");
        }

        if (interface_->Link->OperSettings != nullptr)
        {
            j["operSettings"]["autoNegotiation"] = interface_->Link->OperSettings->AutoNegotiation ? string("true") : string("false");
            j["operSettings"]["speed"] = to_string(interface_->Link->OperSettings->Speed);
            j["operSettings"]["duplex"] = interface_->Link->OperSettings->Duplex == tt__Duplex__Full ? string("full") : string("half");
        }

        j["interfaceType"] = to_string(interface_->Link->InterfaceType);
    }

    if (interface_->IPv4 != nullptr)
    {
        j["IPv4"]["enabled"] = interface_->IPv4->Enabled ? string("true") : string("false");

        if (interface_->IPv4->Config != nullptr)
        {
            vector<json> manual;
            for (int i = 0; i < interface_->IPv4->Config->__sizeManual; i++)
            {
                json item;
                item["address"] = interface_->IPv4->Config->Manual[i]->Address ? string(interface_->IPv4->Config->Manual[i]->Address) : string("");
                item["prefixLength"] = to_string(interface_->IPv4->Config->Manual[i]->PrefixLength);
                manual.push_back(item);
            }
            j["IPv4"]["config"]["manual"] = manual;

            if (interface_->IPv4->Config->LinkLocal != nullptr)
            {

                json linkLocal;
                linkLocal["address"] = interface_->IPv4->Config->LinkLocal->Address ? string(interface_->IPv4->Config->LinkLocal->Address) : string("");
                linkLocal["prefixLength"] = to_string(interface_->IPv4->Config->LinkLocal->PrefixLength);
                j["IPv4"]["config"]["linkLocal"] = linkLocal;
            }

            if (interface_->IPv4->Config->FromDHCP != nullptr)
            {
                json fromDHCP;
                fromDHCP["address"] = interface_->IPv4->Config->FromDHCP->Address ? string(interface_->IPv4->Config->FromDHCP->Address) : string("");
                fromDHCP["prefixLength"] = to_string(interface_->IPv4->Config->FromDHCP->PrefixLength);
                j["IPv4"]["config"]["fromDHCP"] = fromDHCP;
            }

            j["IPv4"]["config"]["useDHCP"] = interface_->IPv4->Config->DHCP ? "true" : "false";
        }
    }

    if (interface_->IPv6 != nullptr)
    {
        j["IPv6"]["enabled"] = interface_->IPv6->Enabled ? string("true") : string("false");

        if (interface_->IPv6->Config != nullptr)
        {
            vector<json> manual;
            for (int i = 0; i < interface_->IPv6->Config->__sizeManual; i++)
            {
                json item;
                item["address"] = interface_->IPv6->Config->Manual[i]->Address ? string(interface_->IPv6->Config->Manual[i]->Address) : string("");
                item["prefixLength"] = to_string(interface_->IPv6->Config->Manual[i]->PrefixLength);
                manual.push_back(item);
            }
            j["IPv6"]["config"]["manual"] = manual;

            vector<json> linkLocal;
            for (int i = 0; i < interface_->IPv6->Config->__sizeLinkLocal; i++)
            {

                json item;
                item["address"] = interface_->IPv6->Config->LinkLocal[i]->Address ? string(interface_->IPv6->Config->LinkLocal[i]->Address) : string("");
                item["prefixLength"] = to_string(interface_->IPv6->Config->LinkLocal[i]->PrefixLength);
                linkLocal.push_back(item);
            }
            j["IPv6"]["config"]["linkLocal"] = linkLocal;

            vector<json> fromDHCP;
            for (int i = 0; i < interface_->IPv6->Config->__sizeFromDHCP; i++)
            {

                json item;
                item["address"] = interface_->IPv6->Config->FromDHCP[i]->Address ? string(interface_->IPv6->Config->FromDHCP[i]->Address) : string("");
                item["prefixLength"] = to_string(interface_->IPv6->Config->FromDHCP[i]->PrefixLength);
                fromDHCP.push_back(item);
            }
            j["IPv6"]["config"]["fromDHCP"] = fromDHCP;

            vector<json> fromRA;
            for (int i = 0; i < interface_->IPv6->Config->__sizeFromRA; i++)
            {

                json item;
                item["address"] = interface_->IPv6->Config->FromRA[i]->Address ? string(interface_->IPv6->Config->FromRA[i]->Address) : string("");
                item["prefixLength"] = to_string(interface_->IPv6->Config->FromRA[i]->PrefixLength);
                fromRA.push_back(item);
            }
            j["IPv6"]["config"]["fromRA"] = fromRA;

            switch (interface_->IPv6->Config->DHCP)
            {
            case tt__IPv6DHCPConfiguration__Auto:
                j["IPv6"]["config"]["DHCP"] = "auto";
                break;
            case tt__IPv6DHCPConfiguration__Stateful:
                j["IPv6"]["config"]["DHCP"] = "stateful";
                break;
            case tt__IPv6DHCPConfiguration__Stateless:
                j["IPv6"]["config"]["DHCP"] = "stateless";
                break;
            case tt__IPv6DHCPConfiguration__Off:
                j["IPv6"]["config"]["DHCP"] = "off";
                break;
            default:
                break;
            }

            j["IPv6"]["config"]["acceptRouterAdvert"] = interface_->IPv6->Config->AcceptRouterAdvert
                                                            ? (*interface_->IPv6->Config->AcceptRouterAdvert
                                                                   ? string("true")
                                                                   : string("false"))
                                                            : string("");
        }
    }

    if (interface_->Extension != nullptr)
    {
        j["extension"]["interfaceType"] = to_string(interface_->Extension->InterfaceType);

        vector<json> dot11;
        for (int i = 0; i < interface_->Extension->__sizeDot11; i++)
        {
            json item;
            item["alias"] = interface_->Extension->Dot11[i]->Alias ? string(interface_->Extension->Dot11[i]->Alias) : string("");
            item["priority"] = interface_->Extension->Dot11[i]->Priority ? string(interface_->Extension->Dot11[i]->Priority) : string("");

            switch (interface_->Extension->Dot11[i]->Mode)
            {
            case tt__Dot11StationMode__Ad_hoc:
                item["mode"] = "ad-hoc";
                break;
            case tt__Dot11StationMode__Infrastructure:
                item["mode"] = "infrastructure";
                break;
            case tt__Dot11StationMode__Extended:
                item["mode"] = "extended";
                break;
            default:
                break;
            }
            item["SSID"] = interface_->Extension->Dot11[i]->SSID.__ptr ? string((char *)interface_->Extension->Dot11[i]->SSID.__ptr) : string("");

            if (interface_->Extension->Dot11[i]->Security != nullptr)
            {

                switch (interface_->Extension->Dot11[i]->Security->Mode)
                {
                case tt__Dot11SecurityMode__None:
                    item["security"]["mode"] = "none";
                    break;
                case tt__Dot11SecurityMode__WEP:
                    item["security"]["mode"] = "WEP";
                    break;
                case tt__Dot11SecurityMode__PSK:
                    item["security"]["mode"] = "PSK";
                    break;
                case tt__Dot11SecurityMode__Dot1X:
                    item["security"]["mode"] = "dot1X";
                    break;
                case tt__Dot11SecurityMode__Extended:
                    item["security"]["mode"] = "extended";
                    break;
                default:
                    break;
                }

                if (interface_->Extension->Dot11[i]->Security->Algorithm != nullptr)
                {
                    switch (*interface_->Extension->Dot11[i]->Security->Algorithm)
                    {
                    case tt__Dot11Cipher__CCMP:
                        item["security"]["algorithm"] = "CCMP";
                        break;
                    case tt__Dot11Cipher__TKIP:
                        item["security"]["algorithm"] = "TKIP";
                        break;
                    case tt__Dot11Cipher__Any:
                        item["security"]["algorithm"] = "any";
                        break;
                    case tt__Dot11Cipher__Extended:
                        item["security"]["algorithm"] = "extended";
                        break;
                    default:
                        break;
                    }
                }
                item["security"]["dot1XConfigurationToken"] = interface_->Extension->Dot11[i]->Security->Dot1X
                                                                  ? string(interface_->Extension->Dot11[i]->Security->Dot1X)
                                                                  : string("");
                if (interface_->Extension->Dot11[i]->Security->PSK != nullptr)
                {
                    item["security"]["PSK"]["key"] = interface_->Extension->Dot11[i]->Security->PSK->Key->__ptr
                                                         ? string((char *)interface_->Extension->Dot11[i]->Security->PSK->Key->__ptr)
                                                         : string("");
                    item["security"]["PSK"]["passphrase"] = interface_->Extension->Dot11[i]->Security->PSK->Passphrase
                                                                ? string(interface_->Extension->Dot11[i]->Security->PSK->Passphrase)
                                                                : string("");
                }
            }
            dot11.push_back(item);
        }
        j["extension"]["dot11"] = dot11;
    }

    jsonStr = j.dump();
    return nullopt;
}

optional<string> jsonOperation::parseVideoSource(string &jsonStr, tt__VideoSource *videoSource)
{
    string errPrefix = "parseVideoSource error";
    if (videoSource == nullptr)
    {
        return makeErrorStr(errPrefix, "param \"videoSource\" is null");
    }
    json j;

    j["token"] = videoSource->token ? string(videoSource->token) : string("");
    j["framerate"] = to_string(videoSource->Framerate);
    if (videoSource->Resolution != nullptr)
    {
        j["resolution"]["width"] = to_string(videoSource->Resolution->Width);
        j["resolution"]["height"] = to_string(videoSource->Resolution->Height);
    }

    if (videoSource->Extension != nullptr && videoSource->Extension->Imaging != nullptr)
    {
        // v2.0
        auto imaging = videoSource->Extension->Imaging;

        if (imaging->BacklightCompensation != nullptr)
        {
            switch (imaging->BacklightCompensation->Mode)
            {
            case tt__BacklightCompensationMode__OFF:
                j["imaging"]["backlightCompensation"]["mode"] = string("off");
                break;
            case tt__BacklightCompensationMode__ON:
                j["imaging"]["backlightCompensation"]["mode"] = string("on");
                break;
            default:
                break;
            }

            j["imaging"]["backlightCompensation"]["level"] = imaging->BacklightCompensation->Level
                                                                 ? to_string(*imaging->BacklightCompensation->Level)
                                                                 : string("");
        }

        j["imaging"]["brightness"] = imaging->Brightness ? to_string(*imaging->Brightness) : string("");
        j["imaging"]["colorSaturation"] = imaging->ColorSaturation ? to_string(*imaging->ColorSaturation) : string("");
        j["imaging"]["contrast"] = imaging->Contrast ? to_string(*imaging->Contrast) : string("");

        if (imaging->Exposure != nullptr)
        {
            switch (imaging->Exposure->Mode)
            {
            case tt__ExposureMode__AUTO:
                j["imaging"]["exposure"]["mode"] = string("auto");
                break;
            case tt__ExposureMode__MANUAL:
                j["imaging"]["exposure"]["mode"] = string("manual");
                break;

            default:
                break;
            }
            if (imaging->Exposure->Priority != nullptr)
            {
                switch (*imaging->Exposure->Priority)
                {
                case tt__ExposurePriority__LowNoise:
                    j["imaging"]["exposure"]["priority"] = string("lowNoise");
                    break;
                case tt__ExposurePriority__FrameRate:
                    j["imaging"]["exposure"]["priority"] = string("framerate");
                    break;

                default:
                    break;
                }
            }

            if (imaging->Exposure->Window != nullptr)
            {
                j["imaging"]["exposure"]["window"]["left"] = imaging->Exposure->Window->left
                                                                 ? to_string(*imaging->Exposure->Window->left)
                                                                 : string("");
                j["imaging"]["exposure"]["window"]["right"] = imaging->Exposure->Window->right
                                                                  ? to_string(*imaging->Exposure->Window->right)
                                                                  : string("");
                j["imaging"]["exposure"]["window"]["top"] = imaging->Exposure->Window->top
                                                                ? to_string(*imaging->Exposure->Window->top)
                                                                : string("");
                j["imaging"]["exposure"]["window"]["bottom"] = imaging->Exposure->Window->bottom
                                                                   ? to_string(*imaging->Exposure->Window->bottom)
                                                                   : string("");
            }

            j["imaging"]["exposure"]["minExposureTime"] = imaging->Exposure->MinExposureTime
                                                              ? to_string(*imaging->Exposure->MinExposureTime)
                                                              : string("");
            j["imaging"]["exposure"]["maxExposureTime"] = imaging->Exposure->MaxExposureTime
                                                              ? to_string(*imaging->Exposure->MaxExposureTime)
                                                              : string("");
            j["imaging"]["exposure"]["minGain"] = imaging->Exposure->MinGain
                                                      ? to_string(*imaging->Exposure->MinGain)
                                                      : string("");
            j["imaging"]["exposure"]["maxGain"] = imaging->Exposure->MaxGain
                                                      ? to_string(*imaging->Exposure->MaxGain)
                                                      : string("");
            j["imaging"]["exposure"]["minIris"] = imaging->Exposure->MinIris
                                                      ? to_string(*imaging->Exposure->MinIris)
                                                      : string("");
            j["imaging"]["exposure"]["maxIris"] = imaging->Exposure->MaxIris
                                                      ? to_string(*imaging->Exposure->MaxIris)
                                                      : string("");
            j["imaging"]["exposure"]["exposureTime"] = imaging->Exposure->ExposureTime
                                                           ? to_string(*imaging->Exposure->ExposureTime)
                                                           : string("");
            j["imaging"]["exposure"]["gain"] = imaging->Exposure->Gain
                                                   ? to_string(*imaging->Exposure->Gain)
                                                   : string("");
            j["imaging"]["exposure"]["iris"] = imaging->Exposure->Iris
                                                   ? to_string(*imaging->Exposure->Iris)
                                                   : string("");
        }

        if (imaging->Focus != nullptr)
        {
            j["imaging"]["focus"]["AFMode"] = imaging->Focus->AFMode ? string(imaging->Focus->AFMode) : string("");

            switch (imaging->Focus->AutoFocusMode)
            {
            case tt__AutoFocusMode__AUTO:
                j["imaging"]["focus"]["autoFocusMode"] = string("auto");
                break;
            case tt__AutoFocusMode__MANUAL:
                j["imaging"]["focus"]["autoFocusMode"] = string("manual");
                break;

            default:
                break;
            }
            j["imaging"]["focus"]["defaultSpeed"] = imaging->Focus->DefaultSpeed
                                                        ? to_string(*imaging->Focus->DefaultSpeed)
                                                        : string("");
            j["imaging"]["focus"]["nearLimit"] = imaging->Focus->NearLimit
                                                     ? to_string(*imaging->Focus->NearLimit)
                                                     : string("");
            j["imaging"]["focus"]["farLimit"] = imaging->Focus->FarLimit
                                                    ? to_string(*imaging->Focus->FarLimit)
                                                    : string("");
        }

        if (imaging->IrCutFilter != nullptr)
        {
            switch (*imaging->IrCutFilter)
            {
            case tt__IrCutFilterMode__ON:
                j["imaging"]["irCutFilter"] = string("on");
                break;
            case tt__IrCutFilterMode__OFF:
                j["imaging"]["irCutFilter"] = string("off");
                break;
            case tt__IrCutFilterMode__AUTO:
                j["imaging"]["irCutFilter"] = string("auto");
                break;

            default:
                break;
            }
        }

        j["imaging"]["sharpness"] = imaging->Sharpness
                                        ? to_string(*imaging->Sharpness)
                                        : string("");

        if (imaging->WideDynamicRange != nullptr)
        {
            switch (imaging->WideDynamicRange->Mode)
            {
            case tt__WideDynamicMode__ON:
                j["imaging"]["wideDynamicRange"]["mode"] = string("on");
                break;
            case tt__WideDynamicMode__OFF:
                j["imaging"]["wideDynamicRange"]["mode"] = string("off");
                break;

            default:
                break;
            }

            j["imaging"]["wideDynamicRange"]["level"] = imaging->WideDynamicRange->Level
                                                            ? to_string(*imaging->WideDynamicRange->Level)
                                                            : string("");
        }

        if (imaging->WhiteBalance != nullptr)
        {
            switch (imaging->WhiteBalance->Mode)
            {
            case tt__WhiteBalanceMode__AUTO:
                j["imaging"]["whiteBalance"]["mode"] = string("auto");
                break;
            case tt__WhiteBalanceMode__MANUAL:
                j["imaging"]["whiteBalance"]["mode"] = string("manual");
                break;

            default:
                break;
            }

            j["imaging"]["whiteBalance"]["crGain"] = imaging->WhiteBalance->CrGain
                                                         ? to_string(*imaging->WhiteBalance->CrGain)
                                                         : string("");
            j["imaging"]["whiteBalance"]["cbGain"] = imaging->WhiteBalance->CbGain
                                                         ? to_string(*imaging->WhiteBalance->CbGain)
                                                         : string("");
        }

        if (imaging->Extension != nullptr)
        {
            if (imaging->Extension->ImageStabilization != nullptr)
            {
                switch (imaging->Extension->ImageStabilization->Mode)
                {
                case tt__ImageStabilizationMode__AUTO:
                    j["imaging"]["imageStabilization"]["mode"] = string("auto");
                    break;
                case tt__ImageStabilizationMode__ON:
                    j["imaging"]["imageStabilization"]["mode"] = string("on");
                    break;
                case tt__ImageStabilizationMode__OFF:
                    j["imaging"]["imageStabilization"]["mode"] = string("off");
                    break;
                case tt__ImageStabilizationMode__Extended:
                    j["imaging"]["imageStabilization"]["mode"] = string("extended");
                    break;
                default:
                    break;
                }

                j["imaging"]["imageStabilization"]["level"] = imaging->Extension->ImageStabilization->Level
                                                                  ? to_string(*imaging->Extension->ImageStabilization->Level)
                                                                  : string("");
            }

            if (imaging->Extension->Extension != nullptr)
            {
                auto extension = imaging->Extension->Extension;

                vector<json> irCutFilterAutoAdjustments;
                for (int i = 0; i < extension->__sizeIrCutFilterAutoAdjustment; i++)
                {
                    json item;

                    item["boundaryType"] = extension->IrCutFilterAutoAdjustment[i]->BoundaryType
                                               ? string(extension->IrCutFilterAutoAdjustment[i]->BoundaryType)
                                               : string("");
                    item["boundaryOffset"] = extension->IrCutFilterAutoAdjustment[i]->BoundaryOffset
                                                 ? to_string(*extension->IrCutFilterAutoAdjustment[i]->BoundaryOffset)
                                                 : string("");
                    item["responseTime"] = extension->IrCutFilterAutoAdjustment[i]->ResponseTime
                                               ? string(extension->IrCutFilterAutoAdjustment[i]->ResponseTime)
                                               : string("");

                    irCutFilterAutoAdjustments.push_back(item);
                }
                j["imaging"]["irCutFilterAutoAdjustment"] = irCutFilterAutoAdjustments;

                if (extension->Extension != nullptr)
                {
                    if (extension->Extension->ToneCompensation != nullptr)
                    {
                        j["imaging"]["toneCompensation"]["mode"] = extension->Extension->ToneCompensation->Mode
                                                                       ? string(extension->Extension->ToneCompensation->Mode)
                                                                       : string("");
                        j["imaging"]["toneCompensation"]["level"] = extension->Extension->ToneCompensation->Level
                                                                        ? to_string(*extension->Extension->ToneCompensation->Level)
                                                                        : string("");
                    }

                    if (extension->Extension->Defogging != nullptr)
                    {
                        j["imaging"]["defogging"]["mode"] = extension->Extension->Defogging->Mode
                                                                ? string(extension->Extension->Defogging->Mode)
                                                                : string("");
                        j["imaging"]["defogging"]["level"] = extension->Extension->Defogging->Level
                                                                 ? to_string(*extension->Extension->Defogging->Level)
                                                                 : string("");
                    }

                    if (extension->Extension->NoiseReduction != nullptr)
                    {
                        j["imaging"]["noiseReduction"]["level"] = to_string(extension->Extension->NoiseReduction->Level);
                    }
                }
            }
        }
    }
    else if (videoSource->Imaging != nullptr)
    {
        // v1.0
        auto imaging = videoSource->Imaging;

        if (imaging->BacklightCompensation != nullptr)
        {
            switch (imaging->BacklightCompensation->Mode)
            {
            case tt__BacklightCompensationMode__OFF:
                j["imaging"]["backlightCompensation"]["mode"] = string("off");
                break;
            case tt__BacklightCompensationMode__ON:
                j["imaging"]["backlightCompensation"]["mode"] = string("on");
                break;
            default:
                break;
            }

            j["imaging"]["backlightCompensation"]["level"] = to_string(imaging->BacklightCompensation->Level);
        }

        j["imaging"]["brightness"] = imaging->Brightness ? to_string(*imaging->Brightness) : string("");
        j["imaging"]["colorSaturation"] = imaging->ColorSaturation ? to_string(*imaging->ColorSaturation) : string("");
        j["imaging"]["contrast"] = imaging->Contrast ? to_string(*imaging->Contrast) : string("");

        if (imaging->Exposure != nullptr)
        {
            switch (imaging->Exposure->Mode)
            {
            case tt__ExposureMode__AUTO:
                j["imaging"]["exposure"]["mode"] = string("auto");
                break;
            case tt__ExposureMode__MANUAL:
                j["imaging"]["exposure"]["mode"] = string("manual");
                break;

            default:
                break;
            }
            switch (imaging->Exposure->Priority)
            {
            case tt__ExposurePriority__LowNoise:
                j["imaging"]["exposure"]["priority"] = string("lowNoise");
                break;
            case tt__ExposurePriority__FrameRate:
                j["imaging"]["exposure"]["priority"] = string("framerate");
                break;

            default:
                break;
            }

            if (imaging->Exposure->Window != nullptr)
            {
                j["imaging"]["exposure"]["window"]["left"] = imaging->Exposure->Window->left
                                                                 ? to_string(*imaging->Exposure->Window->left)
                                                                 : string("");
                j["imaging"]["exposure"]["window"]["right"] = imaging->Exposure->Window->right
                                                                  ? to_string(*imaging->Exposure->Window->right)
                                                                  : string("");
                j["imaging"]["exposure"]["window"]["top"] = imaging->Exposure->Window->top
                                                                ? to_string(*imaging->Exposure->Window->top)
                                                                : string("");
                j["imaging"]["exposure"]["window"]["bottom"] = imaging->Exposure->Window->bottom
                                                                   ? to_string(*imaging->Exposure->Window->bottom)
                                                                   : string("");
            }

            j["imaging"]["exposure"]["minExposureTime"] = to_string(imaging->Exposure->MinExposureTime);
            j["imaging"]["exposure"]["maxExposureTime"] = to_string(imaging->Exposure->MaxExposureTime);
            j["imaging"]["exposure"]["minGain"] = to_string(imaging->Exposure->MinGain);
            j["imaging"]["exposure"]["maxGain"] = to_string(imaging->Exposure->MaxGain);
            j["imaging"]["exposure"]["minIris"] = to_string(imaging->Exposure->MinIris);
            j["imaging"]["exposure"]["maxIris"] = to_string(imaging->Exposure->MaxIris);
            j["imaging"]["exposure"]["exposureTime"] = to_string(imaging->Exposure->ExposureTime);
            j["imaging"]["exposure"]["gain"] = to_string(imaging->Exposure->Gain);
            j["imaging"]["exposure"]["iris"] = to_string(imaging->Exposure->Iris);
        }

        if (imaging->Focus != nullptr)
        {
            switch (imaging->Focus->AutoFocusMode)
            {
            case tt__AutoFocusMode__AUTO:
                j["imaging"]["focus"]["autoFocusMode"] = string("auto");
                break;
            case tt__AutoFocusMode__MANUAL:
                j["imaging"]["focus"]["autoFocusMode"] = string("manual");
                break;

            default:
                break;
            }
            j["imaging"]["focus"]["defaultSpeed"] = to_string(imaging->Focus->DefaultSpeed);
            j["imaging"]["focus"]["nearLimit"] = to_string(imaging->Focus->NearLimit);
            j["imaging"]["focus"]["farLimit"] = to_string(imaging->Focus->FarLimit);
        }

        if (imaging->IrCutFilter != nullptr)
        {
            switch (*imaging->IrCutFilter)
            {
            case tt__IrCutFilterMode__ON:
                j["imaging"]["irCutFilter"] = string("on");
                break;
            case tt__IrCutFilterMode__OFF:
                j["imaging"]["irCutFilter"] = string("off");
                break;
            case tt__IrCutFilterMode__AUTO:
                j["imaging"]["irCutFilter"] = string("auto");
                break;

            default:
                break;
            }
        }

        j["imaging"]["sharpness"] = imaging->Sharpness
                                        ? to_string(*imaging->Sharpness)
                                        : string("");

        if (imaging->WideDynamicRange != nullptr)
        {
            switch (imaging->WideDynamicRange->Mode)
            {
            case tt__WideDynamicMode__ON:
                j["imaging"]["wideDynamicRange"]["mode"] = string("on");
                break;
            case tt__WideDynamicMode__OFF:
                j["imaging"]["wideDynamicRange"]["mode"] = string("off");
                break;

            default:
                break;
            }

            j["imaging"]["wideDynamicRange"]["level"] = to_string(imaging->WideDynamicRange->Level);
        }

        if (imaging->WhiteBalance != nullptr)
        {
            switch (imaging->WhiteBalance->Mode)
            {
            case tt__WhiteBalanceMode__AUTO:
                j["imaging"]["whiteBalance"]["mode"] = string("auto");
                break;
            case tt__WhiteBalanceMode__MANUAL:
                j["imaging"]["whiteBalance"]["mode"] = string("manual");
                break;

            default:
                break;
            }

            j["imaging"]["whiteBalance"]["crGain"] = to_string(imaging->WhiteBalance->CrGain);
            j["imaging"]["whiteBalance"]["cbGain"] = to_string(imaging->WhiteBalance->CbGain);
        }
    }

    jsonStr = j.dump();
    return nullopt;
}

optional<string> jsonOperation::parseVideoSourceConfiguration(string &jsonStr, tt__VideoSourceConfiguration *config)
{
    string errPrefix = "parseVideoSourceConfiguration error";
    if (config == nullptr)
    {
        return makeErrorStr(errPrefix, "param \"config\" is null");
    }

    json j;
    j["token"] = config->token ? string(config->token) : string("");
    j["name"] = config->Name ? string(config->Name) : string("");
    j["useCount"] = to_string(config->UseCount);
    j["viewMode"] = config->ViewMode ? string(config->ViewMode) : string("");
    j["sourceToken"] = config->SourceToken ? string(config->SourceToken) : string("");
    j["bounds"] = string("(") + to_string(config->Bounds->x) +
                  string(", ") + to_string(config->Bounds->y) +
                  string(", ") + to_string(config->Bounds->width) +
                  string(", ") + to_string(config->Bounds->height) + string(")");
    if (config->Extension != nullptr)
    {
        json extension;

        if (config->Extension->Rotate != nullptr)
        {
            switch (config->Extension->Rotate->Mode)
            {
            case tt__RotateMode__OFF:
                extension["rotate"]["mode"] = string("off");
                break;
            case tt__RotateMode__ON:
                extension["rotate"]["mode"] = string("on");
                break;
            case tt__RotateMode__AUTO:
                extension["rotate"]["mode"] = string("auto");
                break;
            default:
                break;
            }

            extension["rotate"]["degree"] = config->Extension->Rotate->Degree ? to_string(*config->Extension->Rotate->Degree) : string("");
        }

        if (config->Extension->Extension != nullptr)
        {
            auto extension2 = config->Extension->Extension;

            vector<json> items;
            for (int i = 0; i < extension2->__sizeLensDescription; i++)
            {
                json item;
                item["focalLength"] = extension2->LensDescription[i]->FocalLength ? to_string(*extension2->LensDescription[i]->FocalLength) : string("");
                item["Offset"] = string("(") + to_string(*extension2->LensDescription[i]->Offset->x) +
                                 string(", ") + to_string(*extension2->LensDescription[i]->Offset->y) + string(")");

                vector<json> projections;
                for (int ii = 0; ii < extension2->LensDescription[i]->__sizeProjection; ii++)
                {
                    json projection;

                    projection["angle"] = to_string(extension2->LensDescription[i]->Projection[ii]->Angle);
                    projection["radius"] = to_string(extension2->LensDescription[i]->Projection[ii]->Radius);
                    projection["transmittance"] = extension2->LensDescription[i]->Projection[ii]->Transmittance
                                                      ? to_string(*extension2->LensDescription[i]->Projection[ii]->Transmittance)
                                                      : string("");

                    projections.push_back(projection);
                }
                item["projection"] = projections;
                item["xFactor"] = to_string(extension2->LensDescription[i]->XFactor);

                items.push_back(item);
            }
            extension["extension"]["lensDescription"] = items;

            if (extension2->SceneOrientation != nullptr)
            {
                switch (extension2->SceneOrientation->Mode)
                {
                case tt__SceneOrientationMode__MANUAL:
                    extension["extension"]["sceneOrientation"]["mode"] = string("manual");
                    break;
                case tt__SceneOrientationMode__AUTO:
                    extension["extension"]["sceneOrientation"]["mode"] = string("auto");
                    break;
                default:
                    break;
                }
                extension["extension"]["sceneOrientation"]["orientation"] = extension2->SceneOrientation->Orientation
                                                                                ? string(extension2->SceneOrientation->Orientation)
                                                                                : string("");
            }
        }

        j["extension"] = extension;
    }

    jsonStr = j.dump();
    return nullopt;
}

optional<string> jsonOperation::parseVideoOutputConfiguration(string &jsonStr, tt__VideoOutputConfiguration *config)
{
    string errPrefix = "parseVideoOutputConfiguration error";
    if (config == nullptr)
    {
        return makeErrorStr(errPrefix, "param \"config\" is null");
    }

    json j;
    j["token"] = config->token ? string(config->token) : string("");
    j["name"] = config->Name ? string(config->Name) : string("");
    j["useCount"] = to_string(config->UseCount);
    j["outputToken"] = config->OutputToken ? string(config->OutputToken) : string("");

    jsonStr = j.dump();
    return nullopt;
}

optional<string> jsonOperation::parseVideoSourceConfigurationOptions(string &jsonStr, tt__VideoSourceConfigurationOptions *option)
{
    string errPrefix = "parseVideoSourceConfigurationOptions error";
    if (option == nullptr)
    {
        return makeErrorStr(errPrefix, "param \"option\" is null");
    }

    json j;

    j["maximumNumberOfProfiles"] = option->MaximumNumberOfProfiles ? to_string(*option->MaximumNumberOfProfiles) : string("");
    if (option->BoundsRange != nullptr)
    {

        if (option->BoundsRange->XRange != nullptr)
        {
            j["boundsRange"]["xRange"] = to_string(option->BoundsRange->XRange->Min) + " ~ " + to_string(option->BoundsRange->XRange->Max);
        }

        if (option->BoundsRange->YRange != nullptr)
        {
            j["boundsRange"]["yRange"] = to_string(option->BoundsRange->YRange->Min) + " ~ " + to_string(option->BoundsRange->YRange->Max);
        }

        if (option->BoundsRange->WidthRange != nullptr)
        {
            j["boundsRange"]["widthRange"] = to_string(option->BoundsRange->WidthRange->Min) + " ~ " + to_string(option->BoundsRange->WidthRange->Max);
        }

        if (option->BoundsRange->HeightRange != nullptr)
        {
            j["boundsRange"]["heightRange"] = to_string(option->BoundsRange->HeightRange->Min) + " ~ " + to_string(option->BoundsRange->HeightRange->Max);
        }
    }

    vector<string> videoSourceTokensAvailable;
    for (int i = 0; i < option->__sizeVideoSourceTokensAvailable; i++)
    {
        videoSourceTokensAvailable.push_back(string(option->VideoSourceTokensAvailable[i]));
    }
    j["videoSourceTokensAvailable"] = videoSourceTokensAvailable;

    if (option->Extension != nullptr)
    {
        if (option->Extension->Rotate != nullptr)
        {
            j["extension"]["rotate"]["reboot"] = option->Extension->Rotate->Reboot
                                                     ? (*option->Extension->Rotate->Reboot ? string("true") : string("false"))
                                                     : string("");

            vector<string> mode;
            for (int i = 0; i < option->Extension->Rotate->__sizeMode; i++)
            {
                switch (option->Extension->Rotate->Mode[i])
                {
                case tt__RotateMode__OFF:
                    mode.push_back(string("off"));
                    break;
                case tt__RotateMode__ON:
                    mode.push_back(string("on"));
                    break;
                case tt__RotateMode__AUTO:
                    mode.push_back(string("auto"));
                    break;
                default:
                    break;
                }
            }
            j["extension"]["rotate"]["mode"] = mode;

            if (option->Extension->Rotate->DegreeList != nullptr)
            {
                vector<int> degreeList;
                for (int i = 0; i < option->Extension->Rotate->DegreeList->__sizeItems; i++)
                {
                    degreeList.push_back(option->Extension->Rotate->DegreeList->Items[i]);
                }
                j["extension"]["rotate"]["degreeList"] = degreeList;
            }
        }

        if (option->Extension->Extension != nullptr)
        {
            vector<string> sceneOrientationMode;
            for (int i = 0; i < option->Extension->Extension->__sizeSceneOrientationMode; i++)
            {
                switch (option->Extension->Extension->SceneOrientationMode[i])
                {
                case tt__SceneOrientationMode__MANUAL:
                    sceneOrientationMode.push_back(string("manual"));
                    break;
                case tt__SceneOrientationMode__AUTO:
                    sceneOrientationMode.push_back(string("auto"));
                    break;

                default:
                    sceneOrientationMode.push_back(string(""));
                    break;
                }
            }
            j["extension"]["sceneOrientationMode"] = sceneOrientationMode;
        }
    }

    jsonStr = j.dump();
    return nullopt;
}

optional<string> jsonOperation::parseVideoSourceMode_V1(string &jsonStr, trt__VideoSourceMode *mode)
{
    string errPrefix = "parseVideoSourceMode_V1 error";
    if (mode == nullptr)
    {
        return makeErrorStr(errPrefix, "param \"mode\" is null");
    }

    json j;

    j["token"] = mode->token ? string(mode->token) : string("");
    j["enabled"] = mode->Enabled
                       ? (*mode->Enabled ? string("true") : string("false"))
                       : string("");
    j["maxFramerate"] = to_string(mode->MaxFramerate);
    if (mode->MaxResolution != nullptr)
    {
        j["maxResolution"]["width"] = to_string(mode->MaxResolution->Width);
        j["maxResolution"]["height"] = to_string(mode->MaxResolution->Height);
    }
    j["encodings"] = mode->Encodings ? string(mode->Encodings) : string("");
    j["reboot"] = mode->Reboot ? string("true") : string("false");
    j["description"] = mode->Description ? string(mode->Description) : string("");

    jsonStr = j.dump();
    return nullopt;
}

optional<string> jsonOperation::parseVideoSourceMode_V2(string &jsonStr, ns1__VideoSourceMode *mode)
{
    string errPrefix = "parseVideoSourceMode_V2 error";
    if (mode == nullptr)
    {
        return makeErrorStr(errPrefix, "param \"mode\" is null");
    }

    json j;

    j["token"] = mode->token ? string(mode->token) : string("");
    j["enabled"] = mode->Enabled
                       ? (*mode->Enabled ? string("true") : string("false"))
                       : string("");
    j["maxFramerate"] = to_string(mode->MaxFramerate);
    if (mode->MaxResolution != nullptr)
    {
        j["maxResolution"]["width"] = to_string(mode->MaxResolution->Width);
        j["maxResolution"]["height"] = to_string(mode->MaxResolution->Height);
    }
    j["encodings"] = mode->Encodings ? string(mode->Encodings) : string("");
    j["reboot"] = mode->Reboot ? string("true") : string("false");
    j["description"] = mode->Description ? string(mode->Description) : string("");

    jsonStr = j.dump();
    return nullopt;
}

optional<string> jsonOperation::parseVideoEncoderConfiguration_V1(string &jsonStr, tt__VideoEncoderConfiguration *config)
{
    string errPrefix = "parseVideoEncoderConfiguration_V1 error";
    if (config == nullptr)
    {
        return makeErrorStr(errPrefix, "param \"config\" is null");
    }

    json j;

    j["token"] = config->token ? string(config->token) : string("");
    j["name"] = config->Name ? string(config->Name) : string("");
    j["useCount"] = to_string(config->UseCount);
    j["guaranteedFramerate"] = config->GuaranteedFrameRate
                                   ? (*config->GuaranteedFrameRate ? string("true") : string("false"))
                                   : string("");
    switch (config->Encoding)
    {
    case tt__VideoEncoding__H264:
        j["encoding"] = string("H264");
        break;
    case tt__VideoEncoding__JPEG:
        j["encoding"] = string("JPEG");
        break;
    case tt__VideoEncoding__MPEG4:
        j["encoding"] = string("MPEG4");
        break;

    default:
        break;
    }

    if (config->Resolution != nullptr)
    {
        j["resolution"]["width"] = to_string(config->Resolution->Width);
        j["resolution"]["height"] = to_string(config->Resolution->Height);
    }

    j["quality"] = to_string(config->Quality);

    if (config->RateControl != nullptr)
    {
        j["rateControl"]["framerateLimit"] = to_string(config->RateControl->FrameRateLimit);
        j["rateControl"]["encodingInterval"] = to_string(config->RateControl->EncodingInterval);
        j["rateControl"]["bitrateLimit"] = to_string(config->RateControl->BitrateLimit);
    }

    if (config->MPEG4 != nullptr)
    {
        j["MPEG4"]["govLength"] = to_string(config->MPEG4->GovLength);
        switch (config->MPEG4->Mpeg4Profile)
        {
        case tt__Mpeg4Profile__ASP:
            j["MPEG4"]["Mpeg4Profile"] = string("asp");
            break;
        case tt__Mpeg4Profile__SP:
            j["MPEG4"]["Mpeg4Profile"] = string("sp");
            break;

        default:
            break;
        }
    }

    if (config->H264 != nullptr)
    {
        j["H264"]["govLength"] = to_string(config->H264->GovLength);
        switch (config->H264->H264Profile)
        {
        case tt__H264Profile__Baseline:
            j["H264"]["H264Profile"] = string("baseline");
            break;
        case tt__H264Profile__Extended:
            j["H264"]["H264Profile"] = string("extended");
            break;
        case tt__H264Profile__High:
            j["H264"]["H264Profile"] = string("high");
            break;
        case tt__H264Profile__Main:
            j["H264"]["H264Profile"] = string("main");
            break;

        default:
            break;
        }
    }

    if (config->Multicast != nullptr)
    {
        if (config->Multicast->Address != nullptr)
        {
            switch (config->Multicast->Address->Type)
            {
            case tt__IPType__IPv4:
                j["multicast"]["address"]["type"] = string("ipv4");
                break;
            case tt__IPType__IPv6:
                j["multicast"]["address"]["type"] = string("ipv6");
                break;
            default:
                break;
            }

            j["multicast"]["address"]["IPv4Address"] = config->Multicast->Address->IPv4Address
                                                           ? string(config->Multicast->Address->IPv4Address)
                                                           : string("");
            j["multicast"]["address"]["IPv6Address"] = config->Multicast->Address->IPv6Address
                                                           ? string(config->Multicast->Address->IPv6Address)
                                                           : string("");
        }

        j["multicast"]["port"] = to_string(config->Multicast->Port);
        j["multicast"]["TTL"] = to_string(config->Multicast->TTL);
        j["multicast"]["autoStart"] = config->Multicast->AutoStart ? string("true") : string("false");
    }
    j["sessionTimeout"] = config->SessionTimeout
                              ? string(config->SessionTimeout)
                              : string("");

    jsonStr = j.dump();
    return nullopt;
}

optional<string> jsonOperation::parseVideoEncoderConfiguration_V2(string &jsonStr, tt__VideoEncoder2Configuration *config)
{
    string errPrefix = "parseVideoEncoderConfiguration_V2 error";
    if (config == nullptr)
    {
        return makeErrorStr(errPrefix, "param \"config\" is null");
    }

    json j;

    j["token"] = config->token ? string(config->token) : string("");
    j["name"] = config->Name ? string(config->Name) : string("");
    j["useCount"] = to_string(config->UseCount);
    j["govLength"] = config->GovLength ? to_string(*config->GovLength) : string("");
    j["profile"] = config->Profile ? string(config->Profile) : string("");
    j["guaranteedFramerate"] = config->GuaranteedFrameRate
                                   ? (*config->GuaranteedFrameRate ? string("true") : string("false"))
                                   : string("");
    j["encoding"] = config->Encoding ? string(config->Encoding) : string("");

    if (config->Resolution != nullptr)
    {
        j["resolution"]["width"] = to_string(config->Resolution->Width);
        j["resolution"]["height"] = to_string(config->Resolution->Height);
    }

    if (config->RateControl != nullptr)
    {
        j["rateControl"]["framerateLimit"] = to_string(config->RateControl->FrameRateLimit);
        if (config->RateControl->ConstantBitRate != nullptr)
        {
            j["rateControl"]["constantBitRate"] = *config->RateControl->ConstantBitRate ? string("true") : string("false");
        }
        j["rateControl"]["bitrateLimit"] = to_string(config->RateControl->BitrateLimit);
    }

    if (config->Multicast != nullptr)
    {
        if (config->Multicast->Address != nullptr)
        {
            switch (config->Multicast->Address->Type)
            {
            case tt__IPType__IPv4:
                j["multicast"]["address"]["type"] = string("ipv4");
                break;
            case tt__IPType__IPv6:
                j["multicast"]["address"]["type"] = string("ipv6");
                break;
            default:
                break;
            }

            j["multicast"]["address"]["IPv4Address"] = config->Multicast->Address->IPv4Address
                                                           ? string(config->Multicast->Address->IPv4Address)
                                                           : string("");
            j["multicast"]["address"]["IPv6Address"] = config->Multicast->Address->IPv6Address
                                                           ? string(config->Multicast->Address->IPv6Address)
                                                           : string("");
        }

        j["multicast"]["port"] = to_string(config->Multicast->Port);
        j["multicast"]["TTL"] = to_string(config->Multicast->TTL);
        j["multicast"]["autoStart"] = config->Multicast->AutoStart ? string("true") : string("false");
    }

    j["quality"] = to_string(config->Quality);

    jsonStr = j.dump();
    return nullopt;
}

optional<string> jsonOperation::parseVideoEncoderConfigurationOptions_V1(string &jsonStr, tt__VideoEncoderConfigurationOptions *option)
{
    string errPrefix = "parseVideoEncoderConfigurationOptions_V1 error";
    if (option == nullptr)
    {
        return makeErrorStr(errPrefix, "param \"option\" is null");
    }

    json j;

    if (option->GuaranteedFrameRateSupported != nullptr)
    {
        j["guaranteedFramerateSupported"] = *option->GuaranteedFrameRateSupported ? string("true") : string("false");
    }

    if (option->QualityRange != nullptr)
    {
        j["qualityRange"] = to_string(option->QualityRange->Min) + " ~ " + to_string(option->QualityRange->Max);
    }

    // JPEG
    if (option->Extension != nullptr && option->Extension->JPEG != nullptr)
    {
        auto JPEG = option->Extension->JPEG;

        vector<json> resolutionsAvailable;
        for (int i = 0; i < JPEG->__sizeResolutionsAvailable; i++)
        {
            json item;
            item["width"] = to_string(JPEG->ResolutionsAvailable[i]->Width);
            item["height"] = to_string(JPEG->ResolutionsAvailable[i]->Height);
            resolutionsAvailable.push_back(item);
        }
        j["JPEG"]["resolutionsAvailable"] = resolutionsAvailable;

        if (JPEG->FrameRateRange != nullptr)
        {
            j["JPEG"]["framerateRange"] = to_string(JPEG->FrameRateRange->Min) + " ~ " + to_string(JPEG->FrameRateRange->Max);
        }

        if (JPEG->EncodingIntervalRange != nullptr)
        {
            j["JPEG"]["encodingIntervalRange"] = to_string(JPEG->EncodingIntervalRange->Min) +
                                                 " ~ " +
                                                 to_string(JPEG->EncodingIntervalRange->Max);
        }

        if (JPEG->BitrateRange != nullptr)
        {
            j["JPEG"]["bitrateRange"] = to_string(JPEG->BitrateRange->Min) + " ~ " + to_string(JPEG->BitrateRange->Max);
        }
    }
    else
    {
        auto JPEG = option->JPEG;
        if (JPEG != nullptr)
        {
            vector<json> resolutionsAvailable;
            for (int i = 0; i < JPEG->__sizeResolutionsAvailable; i++)
            {
                json item;
                item["width"] = to_string(JPEG->ResolutionsAvailable[i]->Width);
                item["height"] = to_string(JPEG->ResolutionsAvailable[i]->Height);
                resolutionsAvailable.push_back(item);
            }
            j["JPEG"]["resolutionsAvailable"] = resolutionsAvailable;

            if (JPEG->FrameRateRange != nullptr)
            {
                j["JPEG"]["framerateRange"] = to_string(JPEG->FrameRateRange->Min) + " ~ " + to_string(JPEG->FrameRateRange->Max);
            }

            if (JPEG->EncodingIntervalRange != nullptr)
            {
                j["JPEG"]["encodingIntervalRange"] = to_string(JPEG->EncodingIntervalRange->Min) +
                                                     " ~ " +
                                                     to_string(JPEG->EncodingIntervalRange->Max);
            }
        }
    }

    // MPEG4
    if (option->Extension != nullptr && option->Extension->MPEG4 != nullptr)
    {
        auto MPEG4 = option->Extension->MPEG4;
        vector<json> resolutionsAvailable;
        for (int i = 0; i < MPEG4->__sizeResolutionsAvailable; i++)
        {
            json item;
            item["width"] = to_string(MPEG4->ResolutionsAvailable[i]->Width);
            item["height"] = to_string(MPEG4->ResolutionsAvailable[i]->Height);
            resolutionsAvailable.push_back(item);
        }
        j["MPEG4"]["resolutionsAvailable"] = resolutionsAvailable;

        if (MPEG4->GovLengthRange != nullptr)
        {
            j["MPEG4"]["govLengthRange"] = to_string(MPEG4->GovLengthRange->Min) + " ~ " + to_string(MPEG4->GovLengthRange->Max);
        }

        if (MPEG4->FrameRateRange != nullptr)
        {
            j["MPEG4"]["framerateRange"] = to_string(MPEG4->FrameRateRange->Min) + " ~ " + to_string(MPEG4->FrameRateRange->Max);
        }

        if (MPEG4->EncodingIntervalRange != nullptr)
        {
            j["MPEG4"]["encodingIntervalRange"] = to_string(MPEG4->EncodingIntervalRange->Min) +
                                                  " ~ " +
                                                  to_string(MPEG4->EncodingIntervalRange->Max);
        }

        vector<string> mpeg4ProfilesSupported;
        for (int i = 0; i < MPEG4->__sizeMpeg4ProfilesSupported; i++)
        {
            switch (MPEG4->Mpeg4ProfilesSupported[i])
            {
            case tt__Mpeg4Profile__ASP:
                mpeg4ProfilesSupported.push_back(string("asp"));
                break;
            case tt__Mpeg4Profile__SP:
                mpeg4ProfilesSupported.push_back(string("sp"));
                break;

            default:
                break;
            }
        }
        j["MPEG4"]["mpeg4ProfilesSupported"] = mpeg4ProfilesSupported;

        if (MPEG4->BitrateRange != nullptr)
        {
            j["MPEG4"]["bitrateRange"] = to_string(MPEG4->BitrateRange->Min) + " ~ " + to_string(MPEG4->BitrateRange->Max);
        }
    }
    else
    {
        auto MPEG4 = option->MPEG4;
        if (MPEG4 != nullptr)
        {
            vector<json> resolutionsAvailable;
            for (int i = 0; i < MPEG4->__sizeResolutionsAvailable; i++)
            {
                json item;
                item["width"] = to_string(MPEG4->ResolutionsAvailable[i]->Width);
                item["height"] = to_string(MPEG4->ResolutionsAvailable[i]->Height);
                resolutionsAvailable.push_back(item);
            }
            j["MPEG4"]["resolutionsAvailable"] = resolutionsAvailable;

            if (MPEG4->GovLengthRange != nullptr)
            {
                j["MPEG4"]["govLengthRange"] = to_string(MPEG4->GovLengthRange->Min) + " ~ " + to_string(MPEG4->GovLengthRange->Max);
            }

            if (MPEG4->FrameRateRange != nullptr)
            {
                j["MPEG4"]["framerateRange"] = to_string(MPEG4->FrameRateRange->Min) + " ~ " + to_string(MPEG4->FrameRateRange->Max);
            }

            if (MPEG4->EncodingIntervalRange != nullptr)
            {
                j["MPEG4"]["encodingIntervalRange"] = to_string(MPEG4->EncodingIntervalRange->Min) +
                                                      " ~ " +
                                                      to_string(MPEG4->EncodingIntervalRange->Max);
            }

            vector<string> mpeg4ProfilesSupported;
            for (int i = 0; i < MPEG4->__sizeMpeg4ProfilesSupported; i++)
            {
                switch (MPEG4->Mpeg4ProfilesSupported[i])
                {
                case tt__Mpeg4Profile__ASP:
                    mpeg4ProfilesSupported.push_back(string("asp"));
                    break;
                case tt__Mpeg4Profile__SP:
                    mpeg4ProfilesSupported.push_back(string("sp"));
                    break;

                default:
                    break;
                }
            }
            j["MPEG4"]["mpeg4ProfilesSupported"] = mpeg4ProfilesSupported;
        }
    }

    // H264
    if (option->Extension != nullptr && option->Extension->H264 != nullptr)
    {
        auto H264 = option->Extension->H264;

        vector<json> resolutionsAvailable;
        for (int i = 0; i < H264->__sizeResolutionsAvailable; i++)
        {
            json item;
            item["width"] = to_string(H264->ResolutionsAvailable[i]->Width);
            item["height"] = to_string(H264->ResolutionsAvailable[i]->Height);
            resolutionsAvailable.push_back(item);
        }
        j["H264"]["resolutionsAvailable"] = resolutionsAvailable;

        if (H264->GovLengthRange != nullptr)
        {
            j["H264"]["govLengthRange"] = to_string(H264->GovLengthRange->Min) + " ~ " + to_string(H264->GovLengthRange->Max);
        }

        if (H264->FrameRateRange != nullptr)
        {
            j["H264"]["framerateRange"] = to_string(H264->FrameRateRange->Min) + " ~ " + to_string(H264->FrameRateRange->Max);
        }

        if (H264->EncodingIntervalRange != nullptr)
        {
            j["H264"]["encodingIntervalRange"] = to_string(H264->EncodingIntervalRange->Min) +
                                                 " ~ " +
                                                 to_string(H264->EncodingIntervalRange->Max);
        }

        vector<string> H264ProfilesSupported;
        for (int i = 0; i < H264->__sizeH264ProfilesSupported; i++)
        {
            switch (H264->H264ProfilesSupported[i])
            {
            case tt__H264Profile__Baseline:
                H264ProfilesSupported.push_back(string("baseline"));
                break;
            case tt__H264Profile__Extended:
                H264ProfilesSupported.push_back(string("extended"));
                break;
            case tt__H264Profile__High:
                H264ProfilesSupported.push_back(string("high"));
                break;
            case tt__H264Profile__Main:
                H264ProfilesSupported.push_back(string("main"));
                break;

            default:
                break;
            }
        }
        j["H264"]["H264ProfilesSupported"] = H264ProfilesSupported;

        if (H264->BitrateRange != nullptr)
        {
            j["H264"]["bitrateRange"] = to_string(H264->BitrateRange->Min) + " ~ " + to_string(H264->BitrateRange->Max);
        }
    }
    else
    {
        auto H264 = option->H264;
        if (H264 != nullptr)
        {
            vector<json> resolutionsAvailable;
            for (int i = 0; i < H264->__sizeResolutionsAvailable; i++)
            {
                json item;
                item["width"] = to_string(H264->ResolutionsAvailable[i]->Width);
                item["height"] = to_string(H264->ResolutionsAvailable[i]->Height);
                resolutionsAvailable.push_back(item);
            }
            j["H264"]["resolutionsAvailable"] = resolutionsAvailable;

            if (H264->GovLengthRange != nullptr)
            {
                j["H264"]["govLengthRange"] = to_string(H264->GovLengthRange->Min) + " ~ " + to_string(H264->GovLengthRange->Max);
            }

            if (H264->FrameRateRange != nullptr)
            {
                j["H264"]["framerateRange"] = to_string(H264->FrameRateRange->Min) + " ~ " + to_string(H264->FrameRateRange->Max);
            }

            if (H264->EncodingIntervalRange != nullptr)
            {
                j["H264"]["encodingIntervalRange"] = to_string(H264->EncodingIntervalRange->Min) +
                                                     " ~ " +
                                                     to_string(H264->EncodingIntervalRange->Max);
            }

            vector<string> H264ProfilesSupported;
            for (int i = 0; i < H264->__sizeH264ProfilesSupported; i++)
            {
                switch (H264->H264ProfilesSupported[i])
                {
                case tt__H264Profile__Baseline:
                    H264ProfilesSupported.push_back(string("baseline"));
                    break;
                case tt__H264Profile__Extended:
                    H264ProfilesSupported.push_back(string("extended"));
                    break;
                case tt__H264Profile__High:
                    H264ProfilesSupported.push_back(string("high"));
                    break;
                case tt__H264Profile__Main:
                    H264ProfilesSupported.push_back(string("main"));
                    break;

                default:
                    break;
                }
            }
            j["H264"]["H264ProfilesSupported"] = H264ProfilesSupported;
        }
    }

    jsonStr = j.dump();
    return nullopt;
}

optional<string> jsonOperation::parseVideoEncoderConfigurationOptions_V2(string &jsonStr, tt__VideoEncoder2ConfigurationOptions *option)
{
    string errPrefix = "parseVideoEncoderConfigurationOptions_V2 error";
    if (option == nullptr)
    {
        return makeErrorStr(errPrefix, "param \"option\" is null");
    }

    json j;
    j["govLengthRange"] = option->GovLengthRange ? string(option->GovLengthRange) : string("");
    j["frameRatesSupported"] = option->FrameRatesSupported ? string(option->FrameRatesSupported) : string("");
    j["profilesSupported"] = option->ProfilesSupported ? string(option->ProfilesSupported) : string("");

    if (option->ConstantBitRateSupported)
    {
        j["constantBitRateSupported"] = *option->ConstantBitRateSupported ? string("true") : string("false");
    }

    if (option->GuaranteedFrameRateSupported != nullptr)
    {
        j["guaranteedFramerateSupported"] = *option->GuaranteedFrameRateSupported ? string("true") : string("false");
    }

    j["encoding"] = option->Encoding ? string(option->Encoding) : string("");

    if (option->QualityRange != nullptr)
    {
        j["qualityRange"] = to_string(option->QualityRange->Min) + " ~ " + to_string(option->QualityRange->Max);
    }

    vector<json> resolutionsAvailable;
    for (int i = 0; i < option->__sizeResolutionsAvailable; i++)
    {
        json item;
        item["width"] = to_string(option->ResolutionsAvailable[i]->Width);
        item["height"] = to_string(option->ResolutionsAvailable[i]->Height);
        resolutionsAvailable.push_back(item);
    }
    j["resolutionsAvailable"] = resolutionsAvailable;

    if (option->BitrateRange != nullptr)
    {
        j["bitrateRange"] = to_string(option->BitrateRange->Min) + " ~ " + to_string(option->BitrateRange->Max);
    }

    jsonStr = j.dump();
    return nullopt;
}

optional<string> jsonOperation::parseAudioSourceConfiguration(string &jsonStr, tt__AudioSourceConfiguration *config)
{
    string errPrefix = "parseAudioSourceConfiguration error";
    if (config == nullptr)
    {
        return makeErrorStr(errPrefix, "param \"config\" is null");
    }

    json j;

    j["token"] = config->token ? string(config->token) : string("");
    j["name"] = config->Name ? string(config->Name) : string("");
    j["useCount"] = to_string(config->UseCount);
    j["sourceToken"] = config->SourceToken ? string(config->SourceToken) : string("");

    jsonStr = j.dump();
    return nullopt;
}

optional<string> jsonOperation::parseAudioOutputConfiguration(string &jsonStr, tt__AudioOutputConfiguration *config)
{
    string errPrefix = "parseAudioOutputConfiguration error";
    if (config == nullptr)
    {
        return makeErrorStr(errPrefix, "param \"config\" is null");
    }

    json j;
    j["token"] = config->token ? string(config->token) : string("");
    j["name"] = config->Name ? string(config->Name) : string("");
    j["useCount"] = to_string(config->UseCount);
    j["outputToken"] = config->OutputToken ? string(config->OutputToken) : string("");
    j["sendPrimacy"] = config->SendPrimacy ? string(config->SendPrimacy) : string("");
    j["outputLevel"] = to_string(config->OutputLevel);

    jsonStr = j.dump();
    return nullopt;
}

optional<string> jsonOperation::parseAudioOutputConfigurationOptions(string &jsonStr, tt__AudioOutputConfigurationOptions *option)
{
    string errPrefix = "parseAudioOutputConfigurationOptions error";
    if (option == nullptr)
    {
        return makeErrorStr(errPrefix, "param \"option\" is null");
    }

    json j;

    vector<string> outputTokensAvailable;
    for (int i = 0; i < option->__sizeOutputTokensAvailable; i++)
    {
        outputTokensAvailable.push_back(string(option->OutputTokensAvailable[i]));
    }
    j["outputTokensAvailable"] = outputTokensAvailable;

    vector<string> sendPrimacyOptions;
    for (int i = 0; i < option->__sizeSendPrimacyOptions; i++)
    {
        sendPrimacyOptions.push_back(string(option->SendPrimacyOptions[i]));
    }
    j["sendPrimacyOptions"] = sendPrimacyOptions;

    j["outputLevelRange"] = to_string(option->OutputLevelRange->Min) + " ~ " + to_string(option->OutputLevelRange->Max);

    jsonStr = j.dump();
    return nullopt;
}

optional<string> jsonOperation::parseAudioEncoderConfiguration_V1(string &jsonStr, tt__AudioEncoderConfiguration *config)
{
    string errPrefix = "parseAudioEncoderConfiguration_V1 error";
    if (config == nullptr)
    {
        return makeErrorStr(errPrefix, "param \"config\" is null");
    }

    json j;

    j["token"] = config->token ? string(config->token) : string("");
    j["name"] = config->Name ? string(config->Name) : string("");
    j["useCount"] = to_string(config->UseCount);

    switch (config->Encoding)
    {
    case tt__AudioEncoding__AAC:
        j["encoding"] = string("aac");
        break;
    case tt__AudioEncoding__G711:
        j["encoding"] = string("g711");
        break;
    case tt__AudioEncoding__G726:
        j["encoding"] = string("g726");
        break;

    default:
        break;
    }

    j["bitrate"] = to_string(config->Bitrate);
    j["sampleRate"] = to_string(config->SampleRate);

    if (config->Multicast != nullptr)
    {
        if (config->Multicast->Address != nullptr)
        {
            switch (config->Multicast->Address->Type)
            {
            case tt__IPType__IPv4:
                j["multicast"]["address"]["type"] = string("ipv4");
                break;
            case tt__IPType__IPv6:
                j["multicast"]["address"]["type"] = string("ipv6");
                break;

            default:
                break;
            }

            j["multicast"]["address"]["IPv4Address"] = config->Multicast->Address->IPv4Address
                                                           ? string(config->Multicast->Address->IPv4Address)
                                                           : string("");
            j["multicast"]["address"]["IPv6Address"] = config->Multicast->Address->IPv6Address
                                                           ? string(config->Multicast->Address->IPv6Address)
                                                           : string("");
        }

        j["multicast"]["port"] = to_string(config->Multicast->Port);
        j["multicast"]["TTL"] = to_string(config->Multicast->TTL);
        j["multicast"]["autoStart"] = config->Multicast->AutoStart ? string("true") : string("false");
    }

    j["sessionTimeout"] = config->SessionTimeout ? string(config->SessionTimeout) : string("");

    jsonStr = j.dump();
    return nullopt;
}

optional<string> jsonOperation::parseAudioEncoderConfiguration_V2(string &jsonStr, tt__AudioEncoder2Configuration *config)
{
    string errPrefix = "parseAudioEncoderConfiguration_V2 error";
    if (config == nullptr)
    {
        return makeErrorStr(errPrefix, "param \"config\" is null");
    }

    json j;

    j["token"] = config->token ? string(config->token) : string("");
    j["name"] = config->Name ? string(config->Name) : string("");
    j["useCount"] = to_string(config->UseCount);
    j["encoding"] = config->Encoding ? string(config->Encoding) : string("");

    if (config->Multicast != nullptr)
    {
        if (config->Multicast->Address != nullptr)
        {
            switch (config->Multicast->Address->Type)
            {
            case tt__IPType__IPv4:
                j["multicast"]["address"]["type"] = string("ipv4");
                break;
            case tt__IPType__IPv6:
                j["multicast"]["address"]["type"] = string("ipv6");
                break;

            default:
                break;
            }

            j["multicast"]["address"]["IPv4Address"] = config->Multicast->Address->IPv4Address
                                                           ? string(config->Multicast->Address->IPv4Address)
                                                           : string("");
            j["multicast"]["address"]["IPv6Address"] = config->Multicast->Address->IPv6Address
                                                           ? string(config->Multicast->Address->IPv6Address)
                                                           : string("");
        }

        j["multicast"]["port"] = to_string(config->Multicast->Port);
        j["multicast"]["TTL"] = to_string(config->Multicast->TTL);
        j["multicast"]["autoStart"] = config->Multicast->AutoStart ? string("true") : string("false");
    }

    j["bitrate"] = to_string(config->Bitrate);
    j["sampleRate"] = to_string(config->SampleRate);

    jsonStr = j.dump();
    return nullopt;
}

optional<string> jsonOperation::parseAudioEncoderConfigurationOptions(string &jsonStr, tt__AudioEncoderConfigurationOptions *option)
{
    string errPrefix = "parseAudioEncoderConfigurationOptions error";
    if (option == nullptr)
    {
        return makeErrorStr(errPrefix, "param \"option\" is null");
    }

    json j;

    vector<json> optionsVec;
    for (int i = 0; i < option->__sizeOptions; i++)
    {
        json optionItem;

        switch (option->Options[i]->Encoding)
        {
        case tt__AudioEncoding__G711:
            optionItem["encoding"] = string("g711");
            break;
        case tt__AudioEncoding__G726:
            optionItem["encoding"] = string("g726");
            break;
        case tt__AudioEncoding__AAC:
            optionItem["encoding"] = string("aac");
            break;
        default:
            break;
        }

        vector<int> BitrateList;
        for (int ii = 0; ii < option->Options[i]->BitrateList->__sizeItems; ii++)
        {
            BitrateList.push_back(option->Options[i]->BitrateList->Items[ii]);
        }
        optionItem["bitrateList"] = BitrateList;

        vector<int> SampleRateList;
        for (int ii = 0; ii < option->Options[i]->SampleRateList->__sizeItems; ii++)
        {
            SampleRateList.push_back(option->Options[i]->SampleRateList->Items[ii]);
        }
        optionItem["sampleRateList"] = SampleRateList;

        optionsVec.push_back(optionItem);
    }
    j["options"] = optionsVec;

    jsonStr = j.dump();
    return nullopt;
}

optional<string> jsonOperation::parseAudioDecoderConfiguration(string &jsonStr, tt__AudioDecoderConfiguration *config)
{
    string errPrefix = "parseAudioDecoderConfiguration error";
    if (config == nullptr)
    {
        return makeErrorStr(errPrefix, "param \"config\" is null");
    }

    json j;

    j["token"] = config->token ? string(config->token) : string("");
    j["name"] = config->Name ? string(config->Name) : string("");
    j["useCount"] = to_string(config->UseCount);

    jsonStr = j.dump();
    return nullopt;
}

optional<string> jsonOperation::parseAudioDecoderConfigurationOptions_V1(string &jsonStr, tt__AudioDecoderConfigurationOptions *option)
{
    string errPrefix = "parseAudioDecoderConfigurationOptions_V1 error";
    if (option == nullptr)
    {
        return makeErrorStr(errPrefix, "param \"option\" is null");
    }

    json j;

    if (option->AACDecOptions != nullptr)
    {
        if (option->AACDecOptions->Bitrate != nullptr)
        {
            vector<int> bitrate;
            for (int i = 0; i < option->AACDecOptions->Bitrate->__sizeItems; i++)
            {
                bitrate.push_back(option->AACDecOptions->Bitrate->Items[i]);
            }
            j["AACDecOptions"]["bitrate"] = bitrate;
        }

        if (option->AACDecOptions->SampleRateRange != nullptr)
        {
            vector<int> sampleRateRange;
            for (int i = 0; i < option->AACDecOptions->SampleRateRange->__sizeItems; i++)
            {
                sampleRateRange.push_back(option->AACDecOptions->SampleRateRange->Items[i]);
            }
            j["AACDecOptions"]["sampleRateRange"] = sampleRateRange;
        }
    }

    if (option->G711DecOptions != nullptr)
    {
        if (option->G711DecOptions->Bitrate != nullptr)
        {
            vector<int> bitrate;
            for (int i = 0; i < option->G711DecOptions->Bitrate->__sizeItems; i++)
            {
                bitrate.push_back(option->G711DecOptions->Bitrate->Items[i]);
            }
            j["G711DecOptions"]["bitrate"] = bitrate;
        }

        if (option->G711DecOptions->SampleRateRange != nullptr)
        {
            vector<int> sampleRateRange;
            for (int i = 0; i < option->G711DecOptions->SampleRateRange->__sizeItems; i++)
            {
                sampleRateRange.push_back(option->G711DecOptions->SampleRateRange->Items[i]);
            }
            j["G711DecOptions"]["sampleRateRange"] = sampleRateRange;
        }
    }

    if (option->G726DecOptions != nullptr)
    {
        if (option->G726DecOptions->Bitrate != nullptr)
        {
            vector<int> bitrate;
            for (int i = 0; i < option->G726DecOptions->Bitrate->__sizeItems; i++)
            {
                bitrate.push_back(option->G726DecOptions->Bitrate->Items[i]);
            }
            j["G726DecOptions"]["bitrate"] = bitrate;
        }

        if (option->G726DecOptions->SampleRateRange != nullptr)
        {
            vector<int> sampleRateRange;
            for (int i = 0; i < option->G726DecOptions->SampleRateRange->__sizeItems; i++)
            {
                sampleRateRange.push_back(option->G726DecOptions->SampleRateRange->Items[i]);
            }
            j["G726DecOptions"]["sampleRateRange"] = sampleRateRange;
        }
    }

    jsonStr = j.dump();
    return nullopt;
}

optional<string> jsonOperation::parseAudioEncoderDecoderConfigurationOptions_V2(string &jsonStr, tt__AudioEncoder2ConfigurationOptions *option)
{
    string errPrefix = "parseAudioEncoderDecoderConfigurationOptions_V2 error";
    if (option == nullptr)
    {
        return makeErrorStr(errPrefix, "param \"option\" is null");
    }

    json j;

    j["encoding"] = option->Encoding ? string(option->Encoding) : string("");

    if (option->BitrateList != nullptr)
    {
        vector<int> bitrateList;
        for (int i = 0; i < option->BitrateList->__sizeItems; i++)
        {
            bitrateList.push_back(option->BitrateList->Items[i]);
        }
        j["bitrateList"] = bitrateList;
    }

    if (option->SampleRateList != nullptr)
    {
        vector<int> sampleRateList;
        for (int i = 0; i < option->SampleRateList->__sizeItems; i++)
        {
            sampleRateList.push_back(option->SampleRateList->Items[i]);
        }
        j["sampleRateList"] = sampleRateList;
    }

    jsonStr = j.dump();
    return nullopt;
}

optional<string> jsonOperation::parseMetadataConfiguration(string &jsonStr, tt__MetadataConfiguration *config)
{
    string errPrefix = "parseMetadataConfiguration error";
    if (config == nullptr)
    {
        return makeErrorStr(errPrefix, "param \"config\" is null");
    }

    json j;

    j["token"] = config->token ? string(config->token) : string("");
    j["name"] = config->Name ? string(config->Name) : string("");
    j["useCount"] = to_string(config->UseCount);
    j["compressionType"] = config->CompressionType ? string(config->CompressionType) : string("");
    j["geoLocation"] = config->GeoLocation
                           ? (*config->GeoLocation ? string("true") : string("false"))
                           : string("");
    j["shapePolygon"] = config->ShapePolygon
                            ? (*config->ShapePolygon ? string("true") : string("false"))
                            : string("");

    if (config->PTZStatus != nullptr)
    {
        j["PTZStatus"]["status"] = config->PTZStatus->Status ? string("true") : string("false");
        j["PTZStatus"]["position"] = config->PTZStatus->Position ? string("true") : string("false");
    }

    if (config->Events != nullptr)
    {
        j["events"]["filter"] = config->Events->Filter ? string("true") : string("false");
        j["events"]["subscriptionPolicy"] = config->Events->SubscriptionPolicy ? string("true") : string("false");
    }

    j["analytics"] = config->Analytics
                         ? (*config->Analytics ? string("true") : string("false"))
                         : string("");

    if (config->Multicast != nullptr)
    {
        if (config->Multicast->Address != nullptr)
        {
            switch (config->Multicast->Address->Type)
            {
            case tt__IPType__IPv4:
                j["multicast"]["address"]["type"] = string("ipv4");
                break;
            case tt__IPType__IPv6:
                j["multicast"]["address"]["type"] = string("ipv6");
                break;

            default:
                break;
            }

            j["multicast"]["address"]["IPv4Address"] = config->Multicast->Address->IPv4Address
                                                           ? string(config->Multicast->Address->IPv4Address)
                                                           : string("");
            j["multicast"]["address"]["IPv6Address"] = config->Multicast->Address->IPv6Address
                                                           ? string(config->Multicast->Address->IPv6Address)
                                                           : string("");
        }

        j["multicast"]["port"] = to_string(config->Multicast->Port);
        j["multicast"]["TTL"] = to_string(config->Multicast->TTL);
        j["multicast"]["autoStart"] = config->Multicast->AutoStart ? string("true") : string("false");
    }

    j["sessionTimeout"] = config->SessionTimeout ? string(config->SessionTimeout) : string("");

    if (config->AnalyticsEngineConfiguration != nullptr)
    {
        vector<json> analyticsModule;
        for (int i = 0; i < config->AnalyticsEngineConfiguration->__sizeAnalyticsModule; i++)
        {
            string moduleStr;
            if (auto err = parseConfig(moduleStr, config->AnalyticsEngineConfiguration->AnalyticsModule[i]); err)
            {
                return makeErrorStr(errPrefix, *err);
            }
            json item = json::parse(moduleStr);
            analyticsModule.push_back(item);
        }

        j["analyticsModule"] = analyticsModule;
    }

    jsonStr = j.dump();
    return nullopt;
}

optional<string> jsonOperation::parseMetadataConfigurationOptions(string &jsonStr, tt__MetadataConfigurationOptions *option)
{
    string errPrefix = "parseMetadataConfigurationOptions error";
    if (option == nullptr)
    {
        return makeErrorStr(errPrefix, "param \"option\" is null");
    }

    json j;

    if (option->GeoLocation != nullptr)
    {
        j["geoLocation"] = *option->GeoLocation ? string("true") : string("false");
    }

    if (option->MaxContentFilterSize != nullptr)
    {
        j["maxContentFilterSize"] = to_string(*option->MaxContentFilterSize);
    }

    if (option->PTZStatusFilterOptions != nullptr)
    {
        j["PTZStatusFilterOptions"]["panTiltStatusSupported"] = option->PTZStatusFilterOptions->PanTiltStatusSupported
                                                                    ? string("true")
                                                                    : string("false");
        j["PTZStatusFilterOptions"]["zoomStatusSupported"] = option->PTZStatusFilterOptions->ZoomStatusSupported
                                                                 ? string("true")
                                                                 : string("false");
        if (option->PTZStatusFilterOptions->PanTiltPositionSupported != nullptr)
        {
            j["PTZStatusFilterOptions"]["panTiltPositionSupported"] = *option->PTZStatusFilterOptions->PanTiltPositionSupported
                                                                          ? string("true")
                                                                          : string("false");
        }

        if (option->PTZStatusFilterOptions->ZoomPositionSupported != nullptr)
        {
            j["PTZStatusFilterOptions"]["zoomPositionSupported"] = *option->PTZStatusFilterOptions->ZoomPositionSupported
                                                                       ? string("true")
                                                                       : string("false");
        }
    }

    if (option->Extension != nullptr)
    {
        vector<string> compressionType;

        for (int i = 0; i < option->Extension->__sizeCompressionType; i++)
        {
            compressionType.push_back(string(option->Extension->CompressionType[i]));
        }
        j["compressionType"] = compressionType;
    }

    jsonStr = j.dump();
    return nullopt;
}

optional<string> jsonOperation::parseVideoAnalyticsConfiguration(string &jsonStr, tt__VideoAnalyticsConfiguration *config)
{
    string errPrefix = "parseAudioDecoderConfiguration error";
    if (config == nullptr)
    {
        return makeErrorStr(errPrefix, "param \"config\" is null");
    }

    json j;

    j["token"] = config->token ? string(config->token) : string("");
    j["name"] = config->Name ? string(config->Name) : string("");
    j["useCount"] = to_string(config->UseCount);

    if (config->AnalyticsEngineConfiguration != nullptr)
    {
        vector<json> analyticsModules;
        for (int i = 0; i < config->AnalyticsEngineConfiguration->__sizeAnalyticsModule; i++)
        {
            string modulesStr;
            if (auto err = parseConfig(modulesStr, config->AnalyticsEngineConfiguration->AnalyticsModule[i]); err)
            {
                return makeErrorStr(errPrefix, *err);
            }

            json item = json::parse(modulesStr);
            analyticsModules.push_back(item);
        }
        j["analyticsModule"] = analyticsModules;
    }

    if (config->RuleEngineConfiguration != nullptr)
    {
        vector<json> rules;
        for (int i = 0; i < config->RuleEngineConfiguration->__sizeRule; i++)
        {
            string ruleStr;
            if (auto err = parseConfig(ruleStr, config->RuleEngineConfiguration->Rule[i]); err)
            {
                return makeErrorStr(errPrefix, *err);
            }

            json item = json::parse(ruleStr);
            rules.push_back(item);
        }
        j["rule"] = rules;
    }

    jsonStr = j.dump();
    return nullopt;
}

optional<string> jsonOperation::parsePTZConfiguration(string &jsonStr, tt__PTZConfiguration *config)
{
    string errPrefix = "parsePTZConfiguration error";
    if (config == nullptr)
    {
        return makeErrorStr(errPrefix, "param \"config\" is null");
    }

    json j;

    j["token"] = config->token ? string(config->token) : string("");
    j["name"] = config->Name ? string(config->Name) : string("");
    j["useCount"] = to_string(config->UseCount);
    j["moveRamp"] = config->MoveRamp ? to_string(*config->MoveRamp) : string("");
    j["presetRamp"] = config->PresetRamp ? to_string(*config->PresetRamp) : string("");
    j["presetTourRamp"] = config->PresetTourRamp ? to_string(*config->PresetTourRamp) : string("");
    j["nodeToken"] = config->NodeToken ? string(config->NodeToken) : string("");
    j["defaultAbsolutePantTiltPositionSpace"] = config->DefaultAbsolutePantTiltPositionSpace
                                                    ? string(config->DefaultAbsolutePantTiltPositionSpace)
                                                    : string("");
    j["defaultAbsoluteZoomPositionSpace"] = config->DefaultAbsoluteZoomPositionSpace
                                                ? string(config->DefaultAbsoluteZoomPositionSpace)
                                                : string("");
    j["defaultRelativePanTiltTranslationSpace"] = config->DefaultRelativePanTiltTranslationSpace
                                                      ? string(config->DefaultRelativePanTiltTranslationSpace)
                                                      : string("");
    j["defaultRelativeZoomTranslationSpace"] = config->DefaultRelativeZoomTranslationSpace
                                                   ? string(config->DefaultRelativeZoomTranslationSpace)
                                                   : string("");
    j["defaultContinuousPanTiltVelocitySpace"] = config->DefaultContinuousPanTiltVelocitySpace
                                                     ? string(config->DefaultContinuousPanTiltVelocitySpace)
                                                     : string("");
    j["defaultContinuousZoomVelocitySpace"] = config->DefaultContinuousZoomVelocitySpace
                                                  ? string(config->DefaultContinuousZoomVelocitySpace)
                                                  : string("");

    if (config->DefaultPTZSpeed != nullptr)
    {
        if (config->DefaultPTZSpeed->PanTilt != nullptr)
        {
            j["defaultPTZSpeed"]["panTilt"]["x"] = to_string(config->DefaultPTZSpeed->PanTilt->x);
            j["defaultPTZSpeed"]["panTilt"]["y"] = to_string(config->DefaultPTZSpeed->PanTilt->y);
            j["defaultPTZSpeed"]["panTilt"]["space"] = config->DefaultPTZSpeed->PanTilt->space
                                                           ? string(config->DefaultPTZSpeed->PanTilt->space)
                                                           : string("");
        }

        if (config->DefaultPTZSpeed->Zoom != nullptr)
        {
            j["defaultPTZSpeed"]["zoom"]["x"] = to_string(config->DefaultPTZSpeed->Zoom->x);
            j["defaultPTZSpeed"]["zoom"]["space"] = config->DefaultPTZSpeed->Zoom->space
                                                        ? string(config->DefaultPTZSpeed->Zoom->space)
                                                        : string("");
        }
    }

    j["defaultPTZTimeout"] = config->DefaultPTZTimeout
                                 ? string(config->DefaultPTZTimeout)
                                 : string("");

    if (config->PanTiltLimits != nullptr && config->PanTiltLimits->Range != nullptr)
    {
        string rangeStr;
        if (auto err = parse2DSpace(rangeStr, config->PanTiltLimits->Range); err)
        {
            return makeErrorStr(errPrefix, *err);
        }
        json range = json::parse(rangeStr);
        j["panTiltLimits"]["range"] = range;
    }

    if (config->ZoomLimits != nullptr && config->ZoomLimits->Range != nullptr)
    {
        string rangeStr;
        if (auto err = parse1DSpace(rangeStr, config->ZoomLimits->Range); err)
        {
            return makeErrorStr(errPrefix, *err);
        }
        json range = json::parse(rangeStr);
        j["zoomLimits"]["range"] = range;
    }

    if (config->Extension != nullptr && config->Extension->PTControlDirection != nullptr)
    {
        if (config->Extension->PTControlDirection->EFlip != nullptr)
        {
            switch (config->Extension->PTControlDirection->EFlip->Mode)
            {
            case tt__EFlipMode__Extended:
                j["EFlipMode"] = string("extended");
                break;
            case tt__EFlipMode__OFF:
                j["EFlipMode"] = string("off");
                break;
            case tt__EFlipMode__ON:
                j["EFlipMode"] = string("on");
                break;

            default:
                break;
            }
        }

        if (config->Extension->PTControlDirection->Reverse != nullptr)
        {
            switch (config->Extension->PTControlDirection->Reverse->Mode)
            {
            case tt__ReverseMode__Extended:
                j["reverseMode"] = string("extended");
                break;
            case tt__ReverseMode__OFF:
                j["reverseMode"] = string("off");
                break;
            case tt__ReverseMode__ON:
                j["reverseMode"] = string("on");
                break;
            case tt__ReverseMode__AUTO:
                j["reverseMode"] = string("auto");
                break;

            default:
                break;
            }
        }
    }

    jsonStr = j.dump();
    return nullopt;
}

optional<string> jsonOperation::parsePTZConfigurationOptions(string &jsonStr, tt__PTZConfigurationOptions *option)
{
    string errPrefix = "parsePTZConfigurationOptions error";
    if (option == nullptr)
    {
        return makeErrorStr(errPrefix, "param \"option\" is null");
    }

    json j;

    j["PTZRamps"] = option->PTZRamps ? string(option->PTZRamps) : string("");

    if (option->Spaces != nullptr)
    {
        string ptzSpace;
        if (auto err = parsePTZSpace(ptzSpace, option->Spaces); err)
        {
            return makeErrorStr(errPrefix, *err);
        }
        json item = json::parse(ptzSpace);
        j["spaces"] = item;
    }

    if (option->PTZTimeout != nullptr)
    {
        j["PTZTimeout"]["min"] = option->PTZTimeout->Min ? string(option->PTZTimeout->Min) : string("");
        j["PTZTimeout"]["max"] = option->PTZTimeout->Max ? string(option->PTZTimeout->Max) : string("");
    }

    if (option->PTControlDirection != nullptr)
    {
        if (option->PTControlDirection->EFlip != nullptr)
        {
            vector<string> modes;
            for (int i = 0; i < option->PTControlDirection->EFlip->__sizeMode; i++)
            {
                switch (option->PTControlDirection->EFlip->Mode[i])
                {
                case tt__EFlipMode__Extended:
                    modes.push_back(string("extended"));
                    break;
                case tt__EFlipMode__OFF:
                    modes.push_back(string("off"));
                    break;
                case tt__EFlipMode__ON:
                    modes.push_back(string("on"));
                    break;

                default:
                    break;
                }
            }
            j["PTControlDirection"]["EFlipMode"] = modes;
        }

        if (option->PTControlDirection->Reverse != nullptr)
        {
            vector<string> modes;
            for (int i = 0; i < option->PTControlDirection->Reverse->__sizeMode; i++)
            {
                switch (option->PTControlDirection->Reverse->Mode[i])
                {
                case tt__ReverseMode__Extended:
                    modes.push_back(string("extended"));
                    break;
                case tt__ReverseMode__OFF:
                    modes.push_back(string("off"));
                    break;
                case tt__ReverseMode__ON:
                    modes.push_back(string("on"));
                    break;
                case tt__ReverseMode__AUTO:
                    modes.push_back(string("auto"));
                    break;

                default:
                    break;
                }
            }
            j["PTControlDirection"]["reverseMode"] = modes;
        }
    }

    jsonStr = j.dump();
    return nullopt;
}

optional<string> jsonOperation::parseProfiles_V1(string &jsonStr, tt__Profile *profile)
{
    string errPrefix = "parseProfiles_V1 error";
    if (profile == nullptr)
    {
        return makeErrorStr(errPrefix, "param \"profile\" is null");
    }

    json j;

    j["token"] = profile->token ? string(profile->token) : string("");
    if (profile->fixed)
    {
        j["fixed"] = profile->fixed ? string("true") : string("false");
    }
    j["name"] = profile->Name ? string(profile->Name) : string("");

    if (profile->VideoSourceConfiguration != nullptr)
    {
        string VideoSourceConfiguration;
        if (auto err = parseVideoSourceConfiguration(VideoSourceConfiguration, profile->VideoSourceConfiguration); err)
        {
            return makeErrorStr(errPrefix, *err);
        }
        json item = json::parse(VideoSourceConfiguration);
        j["videoSourceConfiguration"] = item;
    }

    if (profile->AudioSourceConfiguration != nullptr)
    {
        string AudioSourceConfiguration;
        if (auto err = parseAudioSourceConfiguration(AudioSourceConfiguration, profile->AudioSourceConfiguration); err)
        {
            return makeErrorStr(errPrefix, *err);
        }
        json item = json::parse(AudioSourceConfiguration);
        j["audioSourceConfiguration"] = item;
    }

    if (profile->VideoEncoderConfiguration != nullptr)
    {
        string VideoEncoderConfiguration;
        if (auto err = parseVideoEncoderConfiguration_V1(VideoEncoderConfiguration, profile->VideoEncoderConfiguration); err)
        {
            return makeErrorStr(errPrefix, *err);
        }
        json item = json::parse(VideoEncoderConfiguration);
        j["videoEncoderConfiguration"] = item;
    }

    if (profile->AudioEncoderConfiguration != nullptr)
    {
        string AudioEncoderConfiguration;
        if (auto err = parseAudioEncoderConfiguration_V1(AudioEncoderConfiguration, profile->AudioEncoderConfiguration); err)
        {
            return makeErrorStr(errPrefix, *err);
        }
        json item = json::parse(AudioEncoderConfiguration);
        j["audioEncoderConfiguration"] = item;
    }

    if (profile->VideoAnalyticsConfiguration != nullptr)
    {
        string VideoAnalyticsConfiguration;
        if (auto err = parseVideoAnalyticsConfiguration(VideoAnalyticsConfiguration, profile->VideoAnalyticsConfiguration); err)
        {
            return makeErrorStr(errPrefix, *err);
        }
        json item = json::parse(VideoAnalyticsConfiguration);
        j["videoAnalyticsConfiguration"] = item;
    }

    if (profile->PTZConfiguration != nullptr)
    {
        string PTZConfiguration;
        if (auto err = parsePTZConfiguration(PTZConfiguration, profile->PTZConfiguration); err)
        {
            return makeErrorStr(errPrefix, *err);
        }
        json item = json::parse(PTZConfiguration);
        j["PTZConfiguration"] = item;
    }

    if (profile->MetadataConfiguration != nullptr)
    {
        string MetadataConfiguration;
        if (auto err = parseMetadataConfiguration(MetadataConfiguration, profile->MetadataConfiguration); err)
        {
            return makeErrorStr(errPrefix, *err);
        }
        json item = json::parse(MetadataConfiguration);
        j["metadataConfiguration"] = item;
    }

    if (profile->Extension != nullptr && profile->Extension->AudioOutputConfiguration != nullptr)
    {
        string AudioOutputConfiguration;
        if (auto err = parseAudioOutputConfiguration(AudioOutputConfiguration, profile->Extension->AudioOutputConfiguration); err)
        {
            return makeErrorStr(errPrefix, *err);
        }
        json item = json::parse(AudioOutputConfiguration);
        j["audioOutputConfiguration"] = item;
    }

    if (profile->Extension != nullptr && profile->Extension->AudioDecoderConfiguration != nullptr)
    {
        string AudioDecoderConfiguration;
        if (auto err = parseAudioDecoderConfiguration(AudioDecoderConfiguration, profile->Extension->AudioDecoderConfiguration); err)
        {
            return makeErrorStr(errPrefix, *err);
        }
        json item = json::parse(AudioDecoderConfiguration);
        j["audioDecoderConfiguration"] = item;
    }

    jsonStr = j.dump();
    return nullopt;
}

optional<string> jsonOperation::parseProfiles_V2(string &jsonStr, ns1__MediaProfile *profile)
{
    string errPrefix = "parseProfiles_V2 error";
    if (profile == nullptr)
    {
        return makeErrorStr(errPrefix, "param \"profile\" is null");
    }

    json j;

    j["token"] = profile->token ? string(profile->token) : string("");
    if (profile->fixed)
    {
        j["fixed"] = profile->fixed ? string("true") : string("false");
    }
    j["name"] = profile->Name ? string(profile->Name) : string("");

    if (profile->Configurations != nullptr)
    {
        if (profile->Configurations->VideoSource != nullptr)
        {
            string VideoSourceConfiguration;
            if (auto err = parseVideoSourceConfiguration(VideoSourceConfiguration, profile->Configurations->VideoSource); err)
            {
                return makeErrorStr(errPrefix, *err);
            }
            json item = json::parse(VideoSourceConfiguration);
            j["videoSource"] = item;
        }

        if (profile->Configurations->AudioSource != nullptr)
        {
            string AudioSourceConfiguration;
            if (auto err = parseAudioSourceConfiguration(AudioSourceConfiguration, profile->Configurations->AudioSource); err)
            {
                return makeErrorStr(errPrefix, *err);
            }
            json item = json::parse(AudioSourceConfiguration);
            j["audioSource"] = item;
        }

        if (profile->Configurations->VideoEncoder != nullptr)
        {
            string VideoEncoderConfiguration;
            if (auto err = parseVideoEncoderConfiguration_V2(VideoEncoderConfiguration, profile->Configurations->VideoEncoder); err)
            {
                return makeErrorStr(errPrefix, *err);
            }
            json item = json::parse(VideoEncoderConfiguration);
            j["videoEncoder"] = item;
        }

        if (profile->Configurations->AudioEncoder != nullptr)
        {
            string AudioEncoderConfiguration;
            if (auto err = parseAudioEncoderConfiguration_V2(AudioEncoderConfiguration, profile->Configurations->AudioEncoder); err)
            {
                return makeErrorStr(errPrefix, *err);
            }
            json item = json::parse(AudioEncoderConfiguration);
            j["audioEncoder"] = item;
        }

        if (profile->Configurations->Analytics != nullptr)
        {
            string VideoAnalyticsConfiguration;
            if (auto err = parseVideoAnalyticsConfiguration(VideoAnalyticsConfiguration, profile->Configurations->Analytics); err)
            {
                return makeErrorStr(errPrefix, *err);
            }
            json item = json::parse(VideoAnalyticsConfiguration);
            j["analytics"] = item;
        }

        if (profile->Configurations->PTZ != nullptr)
        {
            string PTZConfiguration;
            if (auto err = parsePTZConfiguration(PTZConfiguration, profile->Configurations->PTZ); err)
            {
                return makeErrorStr(errPrefix, *err);
            }
            json item = json::parse(PTZConfiguration);
            j["PTZ"] = item;
        }

        if (profile->Configurations->Metadata != nullptr)
        {
            string MetadataConfiguration;
            if (auto err = parseMetadataConfiguration(MetadataConfiguration, profile->Configurations->Metadata); err)
            {
                return makeErrorStr(errPrefix, *err);
            }
            json item = json::parse(MetadataConfiguration);
            j["metadata"] = item;
        }

        if (profile->Configurations->AudioOutput != nullptr)
        {
            string AudioOutputConfiguration;
            if (auto err = parseAudioOutputConfiguration(AudioOutputConfiguration, profile->Configurations->AudioOutput); err)
            {
                return makeErrorStr(errPrefix, *err);
            }
            json item = json::parse(AudioOutputConfiguration);
            j["audioOutput"] = item;
        }

        if (profile->Configurations->AudioDecoder != nullptr)
        {
            string AudioDecoderConfiguration;
            if (auto err = parseAudioDecoderConfiguration(AudioDecoderConfiguration, profile->Configurations->AudioDecoder); err)
            {
                return makeErrorStr(errPrefix, *err);
            }
            json item = json::parse(AudioDecoderConfiguration);
            j["audioDecoder"] = item;
        }
    }
    jsonStr = j.dump();
    return nullopt;
}

optional<string> jsonOperation::parseOSD(string &jsonStr, tt__OSDConfiguration *config)
{
    string errPrefix = "parseOSD error";
    if (config == nullptr)
    {
        return makeErrorStr(errPrefix, "param \"config\" is null");
    }

    json j;

    j["token"] = config->token ? string(config->token) : string("");

    if (config->VideoSourceConfigurationToken != nullptr)
    {
        j["videoSourceConfigurationToken"] = config->VideoSourceConfigurationToken->__item
                                                 ? string(config->VideoSourceConfigurationToken->__item)
                                                 : string("");
    }

    switch (config->Type)
    {
    case tt__OSDType__Image:
        j["type"] = string("image");
        break;
    case tt__OSDType__Text:
        j["type"] = string("text");
        break;
    case tt__OSDType__Extended:
        j["type"] = string("extended");
        break;
    default:
        break;
    }

    if (config->Position != nullptr)
    {
        j["position"]["type"] = config->Position->Type ? string(config->Position->Type) : string("");
        if (config->Position->Pos != nullptr)
        {
            j["position"]["pos"]["x"] = config->Position->Pos->x ? to_string(*config->Position->Pos->x) : string("");
            j["position"]["pos"]["y"] = config->Position->Pos->y ? to_string(*config->Position->Pos->y) : string("");
        }
    }

    if (config->TextString != nullptr)
    {
        j["textString"]["isPersistentText"] = config->TextString->IsPersistentText
                                                  ? (*config->TextString->IsPersistentText ? string("true") : string("false"))
                                                  : string("");
        j["textString"]["type"] = config->TextString->Type ? string(config->TextString->Type) : string("");
        j["textString"]["dateFormat"] = config->TextString->DateFormat ? string(config->TextString->DateFormat) : string("");
        j["textString"]["timeFormat"] = config->TextString->TimeFormat ? string(config->TextString->TimeFormat) : string("");
        j["textString"]["fontSize"] = config->TextString->FontSize ? to_string(*config->TextString->FontSize) : string("");

        if (config->TextString->FontColor != nullptr)
        {
            j["textString"]["fontColor"]["transparent"] = config->TextString->FontColor->Transparent
                                                              ? to_string(*config->TextString->FontColor->Transparent)
                                                              : string("");
            if (config->TextString->FontColor->Color != nullptr)
            {
                j["textString"]["fontColor"]["color"]["x"] = to_string(config->TextString->FontColor->Color->X);
                j["textString"]["fontColor"]["color"]["y"] = to_string(config->TextString->FontColor->Color->Y);
                j["textString"]["fontColor"]["color"]["z"] = to_string(config->TextString->FontColor->Color->Z);
                j["textString"]["fontColor"]["color"]["colorspace"] = config->TextString->FontColor->Color->Colorspace
                                                                          ? string(config->TextString->FontColor->Color->Colorspace)
                                                                          : string("");
                j["textString"]["fontColor"]["color"]["likelihood"] = config->TextString->FontColor->Color->Likelihood
                                                                          ? to_string(*config->TextString->FontColor->Color->Likelihood)
                                                                          : string("");
            }
        }

        if (config->TextString->BackgroundColor != nullptr)
        {
            j["textString"]["backgroundColor"]["transparent"] = config->TextString->BackgroundColor->Transparent
                                                                    ? to_string(*config->TextString->BackgroundColor->Transparent)
                                                                    : string("");
            if (config->TextString->BackgroundColor->Color != nullptr)
            {
                j["textString"]["backgroundColor"]["color"]["x"] = to_string(config->TextString->BackgroundColor->Color->X);
                j["textString"]["backgroundColor"]["color"]["y"] = to_string(config->TextString->BackgroundColor->Color->Y);
                j["textString"]["backgroundColor"]["color"]["z"] = to_string(config->TextString->BackgroundColor->Color->Z);
                j["textString"]["backgroundColor"]["color"]["colorspace"] = config->TextString->BackgroundColor->Color->Colorspace
                                                                                ? string(config->TextString->BackgroundColor->Color->Colorspace)
                                                                                : string("");
                j["textString"]["backgroundColor"]["color"]["likelihood"] = config->TextString->BackgroundColor->Color->Likelihood
                                                                                ? to_string(*config->TextString->BackgroundColor->Color->Likelihood)
                                                                                : string("");
            }
        }

        j["textString"]["plainText"] = config->TextString->PlainText ? string(config->TextString->PlainText) : string("");
    }

    if (config->Image != nullptr)
    {
        j["imgPath"] = config->Image->ImgPath ? string(config->Image->ImgPath) : string("");
    }

    jsonStr = j.dump();
    return nullopt;
}

optional<string> jsonOperation::parseOSDOptions(string &jsonStr, tt__OSDConfigurationOptions *option)
{
    string errPrefix = "parseOSDOptions error";
    if (option == nullptr)
    {
        return makeErrorStr(errPrefix, "param \"option\" is null");
    }

    json j;

    if (option->MaximumNumberOfOSDs != nullptr)
    {
        j["maximumNumberOfOSDs"]["total"] = to_string(option->MaximumNumberOfOSDs->Total);
        j["maximumNumberOfOSDs"]["image"] = option->MaximumNumberOfOSDs->Image
                                                ? to_string(*option->MaximumNumberOfOSDs->Image)
                                                : string("");
        j["maximumNumberOfOSDs"]["plainText"] = option->MaximumNumberOfOSDs->PlainText
                                                    ? to_string(*option->MaximumNumberOfOSDs->PlainText)
                                                    : string("");
        j["maximumNumberOfOSDs"]["date"] = option->MaximumNumberOfOSDs->Date
                                               ? to_string(*option->MaximumNumberOfOSDs->Date)
                                               : string("");
        j["maximumNumberOfOSDs"]["time"] = option->MaximumNumberOfOSDs->Time
                                               ? to_string(*option->MaximumNumberOfOSDs->Time)
                                               : string("");
        j["maximumNumberOfOSDs"]["dateAndTime"] = option->MaximumNumberOfOSDs->DateAndTime
                                                      ? to_string(*option->MaximumNumberOfOSDs->DateAndTime)
                                                      : string("");
    }

    vector<string> type;
    for (int i = 0; i < option->__sizeType; i++)
    {
        switch (option->Type[i])
        {
        case tt__OSDType__Extended:
            type.push_back(string("extended"));
            break;
        case tt__OSDType__Image:
            type.push_back(string("image"));
            break;
        case tt__OSDType__Text:
            type.push_back(string("text"));
            break;
        default:
            break;
        }
    }
    j["type"] = type;

    vector<string> positionOption;
    for (int i = 0; i < option->__sizePositionOption; i++)
    {
        positionOption.push_back(string(option->PositionOption[i]));
    }
    j["positionOption"] = positionOption;

    if (option->TextOption != nullptr)
    {
        vector<string> textOptionType;
        for (int i = 0; i < option->TextOption->__sizeType; i++)
        {
            textOptionType.push_back(string(option->TextOption->Type[i]));
        }
        j["textOption"]["type"] = textOptionType;

        if (option->TextOption->FontSizeRange)
        {
            j["textOption"]["fontSizeRange"] = to_string(option->TextOption->FontSizeRange->Min) +
                                               " ~ " +
                                               to_string(option->TextOption->FontSizeRange->Max);
        }

        vector<string> dateFormat;
        for (int i = 0; i < option->TextOption->__sizeDateFormat; i++)
        {
            dateFormat.push_back(string(option->TextOption->DateFormat[i]));
        }
        j["textOption"]["dateFormat"] = dateFormat;

        vector<string> timeFormat;
        for (int i = 0; i < option->TextOption->__sizeTimeFormat; i++)
        {
            timeFormat.push_back(string(option->TextOption->TimeFormat[i]));
        }
        j["textOption"]["timeFormat"] = timeFormat;

        if (option->TextOption->FontColor != nullptr)
        {
            auto colorOptions = option->TextOption->FontColor;

            if (colorOptions->Color != nullptr)
            {
                vector<json> colorLists;
                for (int i = 0; i < colorOptions->Color->__sizeColorList; i++)
                {
                    json item;
                    item["x"] = to_string(colorOptions->Color->ColorList[i]->X);
                    item["y"] = to_string(colorOptions->Color->ColorList[i]->Y);
                    item["z"] = to_string(colorOptions->Color->ColorList[i]->Z);
                    item["likelihood"] = colorOptions->Color->ColorList[i]->Likelihood
                                             ? to_string(*colorOptions->Color->ColorList[i]->Likelihood)
                                             : string("");
                    item["colorspace"] = colorOptions->Color->ColorList[i]->Colorspace
                                             ? string(colorOptions->Color->ColorList[i]->Colorspace)
                                             : string("");
                    colorLists.push_back(item);
                }
                j["textOption"]["fontColor"]["colorList"] = colorLists;

                vector<json> colorspaceRange;
                for (int i = 0; i < colorOptions->Color->__sizeColorspaceRange; i++)
                {
                    json item;
                    item["x"] = to_string(colorOptions->Color->ColorspaceRange[i]->X->Min) +
                                string(" ~ ") +
                                to_string(colorOptions->Color->ColorspaceRange[i]->X->Max);
                    item["y"] = to_string(colorOptions->Color->ColorspaceRange[i]->Y->Min) +
                                string(" ~ ") +
                                to_string(colorOptions->Color->ColorspaceRange[i]->Y->Max);
                    item["z"] = to_string(colorOptions->Color->ColorspaceRange[i]->Z->Min) +
                                string(" ~ ") +
                                to_string(colorOptions->Color->ColorspaceRange[i]->Z->Max);
                    item["colorspace"] = colorOptions->Color->ColorspaceRange[i]->Colorspace
                                             ? string(colorOptions->Color->ColorspaceRange[i]->Colorspace)
                                             : string("");
                    colorspaceRange.push_back(item);
                }
                j["textOption"]["fontColor"]["colorspaceRange"] = colorspaceRange;
            }
            if (colorOptions->Transparent != nullptr)
            {
                j["textOption"]["fontColor"]["transparent"] = to_string(colorOptions->Transparent->Min) +
                                                              string(" ~ ") +
                                                              to_string(colorOptions->Transparent->Max);
            }
        }

        if (option->TextOption->BackgroundColor != nullptr)
        {
            auto colorOptions = option->TextOption->BackgroundColor;

            if (colorOptions->Color != nullptr)
            {
                vector<json> colorLists;
                for (int i = 0; i < colorOptions->Color->__sizeColorList; i++)
                {
                    json item;
                    item["x"] = to_string(colorOptions->Color->ColorList[i]->X);
                    item["y"] = to_string(colorOptions->Color->ColorList[i]->Y);
                    item["z"] = to_string(colorOptions->Color->ColorList[i]->Z);
                    item["likelihood"] = colorOptions->Color->ColorList[i]->Likelihood
                                             ? to_string(*colorOptions->Color->ColorList[i]->Likelihood)
                                             : string("");
                    item["colorspace"] = colorOptions->Color->ColorList[i]->Colorspace
                                             ? string(colorOptions->Color->ColorList[i]->Colorspace)
                                             : string("");
                    colorLists.push_back(item);
                }
                j["textOption"]["backgroundColor"]["colorList"] = colorLists;

                vector<json> colorspaceRange;
                for (int i = 0; i < colorOptions->Color->__sizeColorspaceRange; i++)
                {
                    json item;
                    item["x"] = to_string(colorOptions->Color->ColorspaceRange[i]->X->Min) +
                                string(" ~ ") +
                                to_string(colorOptions->Color->ColorspaceRange[i]->X->Max);
                    item["y"] = to_string(colorOptions->Color->ColorspaceRange[i]->Y->Min) +
                                string(" ~ ") +
                                to_string(colorOptions->Color->ColorspaceRange[i]->Y->Max);
                    item["z"] = to_string(colorOptions->Color->ColorspaceRange[i]->Z->Min) +
                                string(" ~ ") +
                                to_string(colorOptions->Color->ColorspaceRange[i]->Z->Max);
                    item["colorspace"] = colorOptions->Color->ColorspaceRange[i]->Colorspace
                                             ? string(colorOptions->Color->ColorspaceRange[i]->Colorspace)
                                             : string("");
                    colorspaceRange.push_back(item);
                }
                j["textOption"]["backgroundColor"]["colorspaceRange"] = colorspaceRange;
            }
            if (colorOptions->Transparent != nullptr)
            {
                j["textOption"]["backgroundColor"]["transparent"] = to_string(colorOptions->Transparent->Min) +
                                                                    string(" ~ ") +
                                                                    to_string(colorOptions->Transparent->Max);
            }
        }
    }

    if (option->ImageOption != nullptr)
    {
        j["imageOption"]["formatsSupported"] = option->ImageOption->FormatsSupported
                                                   ? string(option->ImageOption->FormatsSupported)
                                                   : string("");
        j["imageOption"]["maxSize"] = option->ImageOption->MaxSize
                                          ? to_string(*option->ImageOption->MaxSize)
                                          : string("");
        j["imageOption"]["maxWidth"] = option->ImageOption->MaxWidth
                                           ? to_string(*option->ImageOption->MaxWidth)
                                           : string("");
        j["imageOption"]["maxHeight"] = option->ImageOption->MaxHeight
                                            ? to_string(*option->ImageOption->MaxHeight)
                                            : string("");
        vector<string> imagePath;
        for (int i = 0; i < option->ImageOption->__sizeImagePath; i++)
        {
            imagePath.push_back(string(option->ImageOption->ImagePath[i]));
        }
        j["imageOption"]["imagePath"] = imagePath;
    }

    jsonStr = j.dump();
    return nullopt;
}

optional<string> jsonOperation::parseRecordingInformation(string &jsonStr, tt__RecordingInformation *info)
{
    string errPrefix = "parseRecordingInformation error";
    if (info == nullptr)
    {
        return makeErrorStr(errPrefix, "param \"option\" is null");
    }

    json j;
    j["recordingToken"] = info->RecordingToken ? string(info->RecordingToken) : string("");

    if (info->Source != nullptr)
    {
        j["sourceId"] = info->Source->SourceId ? string(info->Source->SourceId) : string("");
        j["sourceName"] = info->Source->Name ? string(info->Source->Name) : string("");
        j["sourceLocation"] = info->Source->Location ? string(info->Source->Location) : string("");
        j["sourceDescription"] = info->Source->Description
                                     ? string(info->Source->Description)
                                     : string("");
        j["sourceAddress"] = info->Source->Address ? string(info->Source->Address) : string("");
    }

    j["earliestRecording"] = info->EarliestRecording
                                 ? onvifToolUtils::time_tToDateTime(*info->EarliestRecording)
                                 : string("");
    j["latestRecording"] = info->LatestRecording
                               ? onvifToolUtils::time_tToDateTime(*info->LatestRecording)
                               : string("");
    j["content"] = info->Content ? string(info->Content) : string("");

    vector<json> tracks;
    for (int i = 0; i < info->__sizeTrack; i++)
    {
        json item;
        item["trackToken"] = info->Track[i]->TrackToken
                                 ? string(info->Track[i]->TrackToken)
                                 : string("");
        switch (info->Track[i]->TrackType)
        {
        case tt__TrackType__Video:
            item["trackTpye"] = string("video");
            break;
        case tt__TrackType__Audio:
            item["trackTpye"] = string("audio");
            break;
        case tt__TrackType__Metadata:
            item["trackTpye"] = string("metaData");
            break;
        case tt__TrackType__Extended:
            item["trackTpye"] = string("extended");
            break;
        default:
            break;
        }
        item["description"] = info->Track[i]->Description
                                  ? string(info->Track[i]->Description)
                                  : string("");
        item["dataFrom"] = onvifToolUtils::time_tToDateTime(info->Track[i]->DataFrom);
        item["dataTo"] = onvifToolUtils::time_tToDateTime(info->Track[i]->DataTo);
        tracks.push_back(item);
    }
    j["track"] = tracks;
    switch (info->RecordingStatus)
    {
    case tt__RecordingStatus__Initiated:
        j["recordingStatus"] = string("initiated");
        break;
    case tt__RecordingStatus__Recording:
        j["recordingStatus"] = string("recording");
        break;
    case tt__RecordingStatus__Stopped:
        j["recordingStatus"] = string("stopped");
        break;
    case tt__RecordingStatus__Removing:
        j["recordingStatus"] = string("removing");
        break;
    case tt__RecordingStatus__Removed:
        j["recordingStatus"] = string("removed");
        break;
    case tt__RecordingStatus__Unknown:
        j["recordingStatus"] = string("unknown");
        break;

    default:
        break;
    }

    jsonStr = j.dump();
    return nullopt;
}

optional<string> jsonOperation::buildNetworkInterfaceSetConfiguration(tt__NetworkInterfaceSetConfiguration &networkInterface,
                                                                      ONVIF_SET_NETWORK_INTERFACE_PARAM *param)
{
    string errPrefix = "buildNetworkInterfaceSetConfiguration error";

    networkInterface.Enabled = &param->enable;
    networkInterface.MTU = nullptr;
    if (param->MTU != -1)
    {
        networkInterface.MTU = &param->MTU;
    }

    // IPv4的配置
    networkInterface.IPv4 = nullptr;
    if (param->IPv4Enabled)
    {
        networkInterface.IPv4 = new tt__IPv4NetworkInterfaceSetConfiguration;
        tt__IPv4NetworkInterfaceSetConfiguration *IPv4Config = networkInterface.IPv4;
        IPv4Config->Enabled = &param->IPv4Enabled;
        IPv4Config->DHCP = &param->IPv4DHCP;

        IPv4Config->__sizeManual = 0;
        IPv4Config->Manual = nullptr;
        if (!param->IPv4DHCP && param->sizeIPv4 > 0)
        {
            if (param->IPv4PrefixLen == nullptr || param->IPv4Address == nullptr)
            {
                return makeErrorStr(errPrefix, "param error");
            }

            IPv4Config->__sizeManual = param->sizeIPv4;
            IPv4Config->Manual = new tt__PrefixedIPv4Address *[param->sizeIPv4];

            for (int i = 0; i < param->sizeIPv4; i++)
            {
                IPv4Config->Manual[i] = new tt__PrefixedIPv4Address;
                IPv4Config->Manual[i]->PrefixLength = param->IPv4PrefixLen[i];
                IPv4Config->Manual[i]->Address = param->IPv4Address[i];
            }
        }
    }

    // IPv6的配置
    networkInterface.IPv6 = nullptr;
    if (param->IPv6Enabled)
    {
        networkInterface.IPv6 = new tt__IPv6NetworkInterfaceSetConfiguration;
        tt__IPv6NetworkInterfaceSetConfiguration *IPv6Config = networkInterface.IPv6;
        IPv6Config->Enabled = &param->IPv6Enabled;
        IPv6Config->AcceptRouterAdvert = &param->acceptRouterAdvert;
        IPv6Config->DHCP = new tt__IPv6DHCPConfiguration;
        *(IPv6Config->DHCP) = tt__IPv6DHCPConfiguration__Auto;
        switch (param->IPv6DHCP)
        {
        case 0:
            *(IPv6Config->DHCP) = tt__IPv6DHCPConfiguration__Auto;
            break;
        case 1:
            *(IPv6Config->DHCP) = tt__IPv6DHCPConfiguration__Stateful;
            break;
        case 2:
            *(IPv6Config->DHCP) = tt__IPv6DHCPConfiguration__Stateless;
            break;
        case 3:
            *(IPv6Config->DHCP) = tt__IPv6DHCPConfiguration__Off;
            break;
        default:
            break;
        }

        IPv6Config->__sizeManual = 0;
        IPv6Config->Manual = nullptr;
        if (param->IPv6DHCP != 3 && param->sizeIPv6 > 0)
        {
            if (param->IPv6PrefixLen == nullptr || param->IPv6Address == nullptr)
            {
                if (networkInterface.IPv4->Manual != nullptr)
                {
                    for (int i = 0; i < param->sizeIPv4; i++)
                    {
                        delete networkInterface.IPv4->Manual[i];
                    }
                    delete[] networkInterface.IPv4->Manual;
                    networkInterface.IPv4->Manual = nullptr;
                }
                return makeErrorStr(errPrefix, "param error");
            }

            IPv6Config->__sizeManual = param->sizeIPv6;
            IPv6Config->Manual = new tt__PrefixedIPv6Address *[param->sizeIPv6];

            for (int i = 0; i < param->sizeIPv6; i++)
            {
                IPv6Config->Manual[i] = new tt__PrefixedIPv6Address;
                IPv6Config->Manual[i]->PrefixLength = param->IPv6PrefixLen[i];
                IPv6Config->Manual[i]->Address = param->IPv6Address[i];
            }
        }
    }

    // link的配置
    networkInterface.Link = nullptr;
    if (param->link != nullptr)
    {
        networkInterface.Link = new tt__NetworkInterfaceConnectionSetting;
        tt__NetworkInterfaceConnectionSetting *link = networkInterface.Link;
        link->AutoNegotiation = param->link->autoNegotiation;
        link->Speed = param->link->speed;
        link->Duplex = tt__Duplex__Full;
        switch (param->link->duplex)
        {
        case 0:
            link->Duplex = tt__Duplex__Full;
            break;
        case 1:
            link->Duplex = tt__Duplex__Half;
            break;
        default:
            break;
        }
    }

    // extension的配置
    networkInterface.Extension = nullptr;
    if (param->sizeExtension > 0 && param->extension != nullptr)
    {
        networkInterface.Extension = new tt__NetworkInterfaceSetConfigurationExtension;
        tt__NetworkInterfaceSetConfigurationExtension *extension = networkInterface.Extension;
        extension->__sizeDot3 = 0;
        extension->Dot3 = nullptr;
        extension->__sizeDot11 = param->sizeExtension;
        extension->Dot11 = nullptr;
        extension->Extension = nullptr;

        extension->Dot11 = new tt__Dot11Configuration *[param->sizeExtension];

        for (int i = 0; i < param->sizeExtension; i++)
        {
            extension->Dot11[i] = new tt__Dot11Configuration;
            extension->Dot11[i]->Priority = param->extension[i]->priority;
            extension->Dot11[i]->Alias = param->extension[i]->alias;
            extension->Dot11[i]->Mode = tt__Dot11StationMode__Ad_hoc;
            switch (param->extension[i]->mode)
            {
            case 0:
                extension->Dot11[i]->Mode = tt__Dot11StationMode__Ad_hoc;
                break;
            case 1:
                extension->Dot11[i]->Mode = tt__Dot11StationMode__Infrastructure;
                break;
            case 2:
                extension->Dot11[i]->Mode = tt__Dot11StationMode__Extended;
                break;
            default:
                break;
            }

            xsd__hexBinary ssid;
            ssid.__ptr = (unsigned char *)param->extension[i]->SSID;
            ssid.__size = param->extension[i]->sizeSSID;
            extension->Dot11[i]->SSID = ssid;

            extension->Dot11[i]->Security = new tt__Dot11SecurityConfiguration;
            tt__Dot11SecurityConfiguration *security = extension->Dot11[i]->Security;
            security->Mode = tt__Dot11SecurityMode__None;
            switch (param->extension[i]->securityMode)
            {
            case 0:
                security->Mode = tt__Dot11SecurityMode__None;
                break;
            case 1:
                security->Mode = tt__Dot11SecurityMode__WEP;
                break;
            case 2:
                security->Mode = tt__Dot11SecurityMode__PSK;
                break;
            case 3:
                security->Mode = tt__Dot11SecurityMode__Dot1X;
                break;
            case 4:
                security->Mode = tt__Dot11SecurityMode__Extended;
                break;
            default:
                break;
            }

            security->Algorithm = new tt__Dot11Cipher;
            *(security->Algorithm) = tt__Dot11Cipher__CCMP;
            switch (param->extension[i]->securityAlgorithm)
            {
            case 0:
                *(security->Algorithm) = tt__Dot11Cipher__CCMP;
                break;
            case 1:
                *(security->Algorithm) = tt__Dot11Cipher__TKIP;
                break;
            case 2:
                *(security->Algorithm) = tt__Dot11Cipher__Any;
                break;
            case 3:
                *(security->Algorithm) = tt__Dot11Cipher__Extended;
                break;
            default:
                break;
            }

            security->PSK = new tt__Dot11PSKSet;
            security->PSK->Key = new xsd__hexBinary;
            security->PSK->Key->__ptr = (unsigned char *)param->extension[i]->PSKKey;
            security->PSK->Key->__size = strlen(param->extension[i]->PSKKey);
            security->PSK->Passphrase = param->extension[i]->PSKPassphrase;

            security->Dot1X = param->extension[i]->dot1XConfigurationToken;
        }
    }

    return nullopt;
}

void jsonOperation::deleteNetworkInterfaceSetConfiguration(tt__NetworkInterfaceSetConfiguration *networkInterface)
{
    if (networkInterface == nullptr)
    {
        return;
    }

    // 释放IPv4
    if (networkInterface->IPv4)
    {

        // 释放IPv4 Manual
        if (networkInterface->IPv4->__sizeManual > 0 && networkInterface->IPv4->Manual != nullptr)
        {
            for (int i = 0; i < networkInterface->IPv4->__sizeManual; i++)
            {
                delete networkInterface->IPv4->Manual[i];
            }
            delete[] networkInterface->IPv4->Manual;
            networkInterface->IPv4->Manual = nullptr;
        }
        delete networkInterface->IPv4;
        networkInterface->IPv4 = nullptr;
    }

    // 释放IPv6
    if (networkInterface->IPv6)
    {

        // 释放IPv6 DHCP
        delete networkInterface->IPv6->DHCP;
        networkInterface->IPv6->DHCP = nullptr;

        // 释放IPv6 Manual
        if (networkInterface->IPv6->__sizeManual > 0 && networkInterface->IPv6->Manual != nullptr)
        {
            for (int i = 0; i < networkInterface->IPv6->__sizeManual; i++)
            {
                delete networkInterface->IPv6->Manual[i];
            }
            delete[] networkInterface->IPv6->Manual;
            networkInterface->IPv6->Manual = nullptr;
        }
        delete networkInterface->IPv6;
        networkInterface->IPv6 = nullptr;
    }

    // 释放link
    if (networkInterface->Link)
    {
        delete networkInterface->Link;
        networkInterface->Link = nullptr;
    }

    // 释放extension
    if (networkInterface->Extension)
    {

        // 释放Dot11
        // extension->Dot11
        if (networkInterface->Extension->__sizeDot11 > 0 && networkInterface->Extension->Dot11 != nullptr)
        {
            for (int i = 0; i < networkInterface->Extension->__sizeDot11; i++)
            {
                delete networkInterface->Extension->Dot11[i]->Security->PSK->Key;
                delete networkInterface->Extension->Dot11[i]->Security->PSK;
                delete networkInterface->Extension->Dot11[i]->Security->Algorithm;
                delete networkInterface->Extension->Dot11[i]->Security;
                delete networkInterface->Extension->Dot11[i];
            }
            delete[] networkInterface->Extension->Dot11;
            networkInterface->Extension->Dot11 = nullptr;
        }

        delete networkInterface->Extension;
        networkInterface->Extension = nullptr;
    }
}

optional<string> jsonOperation::buildOSDConfiguration(tt__OSDConfiguration &OSD, ONVIF_SET_OSD_PARAM *param)
{
    string errPrefix = "buildOSDConfiguration error";

    // 判断参数是否有效
    if (param == nullptr || param->OSDConfigurationToken == nullptr || param->videoSourceConfigurationToken == nullptr)
    {
        return makeErrorStr(errPrefix, "param error");
    }

    // token
    OSD.token = param->OSDConfigurationToken;

    // VideoSourceConfigurationToken
    OSD.VideoSourceConfigurationToken = new tt__OSDReference();
    OSD.VideoSourceConfigurationToken->__item = param->videoSourceConfigurationToken;

    // type
    switch (param->type)
    {
    case 0:
        OSD.Type = tt__OSDType__Text;
        break;
    case 1:
        OSD.Type = tt__OSDType__Image;
        break;

    default:
        OSD.Type = tt__OSDType__Extended;
        break;
    }

    // Position
    OSD.Position = new tt__OSDPosConfiguration();
    tt__OSDPosConfiguration *Position = OSD.Position;
    Position->Extension = nullptr;
    switch (param->positionType)
    {
    case 0:
        Position->Type = (char *)"UpperLeft";
        break;
    case 1:
        Position->Type = (char *)"UpperRight";
        break;
    case 2:
        Position->Type = (char *)"LowerLeft";
        break;
    case 3:
        Position->Type = (char *)"LowerRight";
        break;

    default:
        Position->Type = (char *)"Custom";
        break;
    }
    if (param->positionType == 4 && param->positionX != nullptr)
    {
        Position->Pos = new tt__Vector();
        Position->Pos->x = param->positionX;
        Position->Pos->y = param->positionY;
    }
    else
    {
        Position->Pos = nullptr;
    }

    if (param->type == 0)
    {
        // TestString
        OSD.TextString = new tt__OSDTextConfiguration();
        tt__OSDTextConfiguration *TestString = OSD.TextString;
        TestString->IsPersistentText = param->isPersistentText;
        switch (param->textType)
        {
        case 0:
            TestString->Type = (char *)"Plain";
            break;
        case 1:
            TestString->Type = (char *)"Date";
            break;
        case 2:
            TestString->Type = (char *)"Time";
            break;
        case 3:
            TestString->Type = (char *)"DateAndTime";
            break;
        default:
            TestString->Type = (char *)"Plain";
            break;
        }

        switch (param->dateFormat)
        {
        case 0:
            TestString->DateFormat = (char *)"M/d/yyyy";
            break;
        case 1:
            TestString->DateFormat = (char *)"MM/dd/yyyy";
            break;
        case 2:
            TestString->DateFormat = (char *)"dd/MM/yyyy";
            break;
        case 3:
            TestString->DateFormat = (char *)"yyyy/MM/dd";
            break;
        case 4:
            TestString->DateFormat = (char *)"yyyy-MM-dd";
            break;
        case 5:
            TestString->DateFormat = (char *)"dddd, MMMM dd, yyyy";
            break;
        case 6:
            TestString->DateFormat = (char *)"MMMM dd, yyyy";
            break;
        case 7:
            TestString->DateFormat = (char *)"dd MMMM, yyyy";
            break;

        default:
            TestString->DateFormat = (char *)"dddd, MMMM dd, yyyy";
            break;
        }
        if (param->textType != 1 && param->textType != 3)
        {
            TestString->DateFormat = nullptr;
        }

        switch (param->timeFormat)
        {
        case 0:
            TestString->TimeFormat = (char *)"h:mm:ss tt";
            break;
        case 1:
            TestString->TimeFormat = (char *)"hh:mm:ss tt";
            break;
        case 2:
            TestString->TimeFormat = (char *)"H:mm:ss";
            break;
        case 3:
            TestString->TimeFormat = (char *)"HH:mm:ss";
            break;

        default:
            TestString->TimeFormat = (char *)"h:mm:ss tt";
            break;
        }
        if (param->textType != 2 && param->textType != 3)
        {
            TestString->TimeFormat = nullptr;
        }

        TestString->FontSize = (int *)param->fontSize;

        if (param->fontColor != nullptr)
        {
            TestString->FontColor = new tt__OSDColor();
            tt__OSDColor *FontColor = TestString->FontColor;
            FontColor->Transparent = (int *)param->fontTransparent;

            FontColor->Color = new tt__Color();
            tt__Color *Color = FontColor->Color;
            Color->X = param->fontColor->x;
            Color->Y = param->fontColor->y;
            Color->Z = param->fontColor->z;
            Color->Likelihood = param->fontColor->likelihood;
            switch (param->fontColor->colorSpace)
            {
            case 0:
                Color->Colorspace = (char *)"http://www.onvif.org/ver10/colorspace/YCbCr";
                break;
            case 1:
                Color->Colorspace = (char *)"http://www.onvif.org/ver10/colorspace/CIELUV";
                break;
            case 2:
                Color->Colorspace = (char *)"http://www.onvif.org/ver10/colorspace/CIELAB";
                break;
            case 3:
                Color->Colorspace = (char *)"http://www.onvif.org/ver10/colorspace/HSV";
                break;

            default:
                break;
            }
        }

        if (param->backgroundColor != nullptr)
        {
            TestString->BackgroundColor = new tt__OSDColor();
            tt__OSDColor *BackgroundColor = TestString->BackgroundColor;
            BackgroundColor->Transparent = (int *)param->backgroundTransparent;
            BackgroundColor->Color = new tt__Color();
            tt__Color *Color2 = BackgroundColor->Color;
            Color2->X = param->backgroundColor->x;
            Color2->Y = param->backgroundColor->y;
            Color2->Z = param->backgroundColor->z;
            Color2->Likelihood = param->backgroundColor->likelihood;
            switch (param->backgroundColor->colorSpace)
            {
            case 0:
                Color2->Colorspace = (char *)"http://www.onvif.org/ver10/colorspace/YCbCr";
                break;
            case 1:
                Color2->Colorspace = (char *)"http://www.onvif.org/ver10/colorspace/CIELUV";
                break;
            case 2:
                Color2->Colorspace = (char *)"http://www.onvif.org/ver10/colorspace/CIELAB";
                break;
            case 3:
                Color2->Colorspace = (char *)"http://www.onvif.org/ver10/colorspace/HSV";
                break;

            default:
                break;
            }
        }

        TestString->PlainText = param->plainText;
        TestString->Extension = nullptr;
        OSD.Image = nullptr;
    }
    else if (param->type == 1)
    {
        OSD.TextString = nullptr;
        OSD.Image = new tt__OSDImgConfiguration();
        tt__OSDImgConfiguration *Image = OSD.Image;
        Image->ImgPath = param->imgPath;
        Image->Extension = nullptr;
    }
    else
    {
        OSD.TextString = nullptr;
        OSD.Image = nullptr;
    }
    OSD.Extension = nullptr;
    return nullopt;
}

void jsonOperation::deleteOSDConfiguration(tt__OSDConfiguration *OSD)
{
    if (OSD == nullptr)
    {
        return;
    }

    if (OSD->VideoSourceConfigurationToken != nullptr)
    {
        delete OSD->VideoSourceConfigurationToken;
        OSD->VideoSourceConfigurationToken = nullptr;
    }

    if (OSD->Position != nullptr)
    {
        if (OSD->Position->Pos != nullptr)
        {
            delete OSD->Position->Pos;
            OSD->Position->Pos = nullptr;
        }
        delete OSD->Position;
        OSD->Position = nullptr;
    }

    if (OSD->TextString != nullptr)
    {
        if (OSD->TextString->FontColor != nullptr)
        {
            if (OSD->TextString->FontColor->Color != nullptr)
            {
                delete OSD->TextString->FontColor->Color;
                OSD->TextString->FontColor->Color = nullptr;
            }
            delete OSD->TextString->FontColor;
            OSD->TextString->FontColor = nullptr;
        }

        if (OSD->TextString->BackgroundColor != nullptr)
        {
            if (OSD->TextString->BackgroundColor->Color != nullptr)
            {
                delete OSD->TextString->BackgroundColor->Color;
                OSD->TextString->BackgroundColor->Color = nullptr;
            }
            delete OSD->TextString->BackgroundColor;
            OSD->TextString->BackgroundColor = nullptr;
        }
        delete OSD->TextString;
        OSD->TextString = nullptr;
    }

    if (OSD->Image != nullptr)
    {
        delete OSD->Image;
        OSD->Image = nullptr;
    }
}

string jsonOperation::makeErrorStr(string errPrefix, string err)
{
    return errPrefix + ": " + err;
}
